Skip to content

Commit

Permalink
Merge ce0f8c5 into 9a0bca2
Browse files Browse the repository at this point in the history
  • Loading branch information
stinos committed May 12, 2021
2 parents 9a0bca2 + ce0f8c5 commit b75690d
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 2 deletions.
35 changes: 33 additions & 2 deletions py/objarray.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,17 @@ STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
}
}

STATIC int typecode_for_comparison(int typecode, bool *is_signed) {
if (typecode == BYTEARRAY_TYPECODE) {
return 'B';
}
if (typecode > 'Z') {
*is_signed = true;
typecode -= 32; // to uppercase
}
return typecode;
}

STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
switch (op) {
Expand Down Expand Up @@ -312,14 +323,34 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
return mp_const_false;
}

case MP_BINARY_OP_EQUAL: {
case MP_BINARY_OP_EQUAL:
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL: {
mp_buffer_info_t lhs_bufinfo;
mp_buffer_info_t rhs_bufinfo;
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
return mp_const_false;
}
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
// mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
// The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
// just check if the typecodes are compatible; for testing equality the types should have the
// same code except for signedness, and not be floating point because nan never equals nan.
// For > and < the types should be the same and unsigned.
// Note that typecode_for_comparison always returns uppercase letters to save code size, hence
// the comparison with otherwise invalid F and D characters representing floating point typecodes.
// No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
bool is_signed = false;
const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_signed);
const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_signed);
if (lhs_code == rhs_code && lhs_code != 'F' && lhs_code != 'D' && (op == MP_BINARY_OP_EQUAL || !is_signed)) {
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
}
// mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
// for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
mp_raise_NotImplementedError(NULL);
}

default:
Expand Down
30 changes: 30 additions & 0 deletions tests/basics/array1.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,23 @@
# equality (CPython requires both sides are array)
print(bytes(array.array('b', [0x61, 0x62, 0x63])) == b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) == b'abc')
print(array.array('B', [0x61, 0x62, 0x63]) == b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) != b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) == b'xyz')
print(array.array('b', [0x61, 0x62, 0x63]) != b'xyz')
print(b'abc' == array.array('b', [0x61, 0x62, 0x63]))
print(b'abc' == array.array('B', [0x61, 0x62, 0x63]))
print(b'abc' != array.array('b', [0x61, 0x62, 0x63]))
print(b'xyz' == array.array('b', [0x61, 0x62, 0x63]))
print(b'xyz' != array.array('b', [0x61, 0x62, 0x63]))

compatible_typecodes = []
for t in ["b", "h", "i", "l", "q"]:
compatible_typecodes.append((t, t))
compatible_typecodes.append((t, t.upper()))
for a, b in compatible_typecodes:
print(array.array(a, [1, 2]) == array.array(b, [1, 2]))

class X(array.array):
pass

Expand All @@ -57,3 +66,24 @@ class X(array.array):
print(X('b', [0x61, 0x62, 0x63]) != b'abc')
print(X('b', [0x61, 0x62, 0x63]) == array.array('b', [0x61, 0x62, 0x63]))
print(X('b', [0x61, 0x62, 0x63]) != array.array('b', [0x61, 0x62, 0x63]))

# other comparisons
for typecode in ["B", "H", "I", "L", "Q"]:
a = array.array(typecode, [1, 1])
print(a < a)
print(a <= a)
print(a > a)
print(a >= a)

al = array.array(typecode, [1, 0])
ab = array.array(typecode, [1, 2])

print(a < al)
print(a <= al)
print(a > al)
print(a >= al)

print(a < ab)
print(a <= ab)
print(a > ab)
print(a >= ab)
12 changes: 12 additions & 0 deletions tests/basics/array_micropython.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@
a = array.array('P')
a.append(1)
print(a[0])

# comparison between mismatching binary layouts is not implemented
typecodes = ["b", "h", "i", "l", "q", "P", "O", "S", "f", "d"]
for a in typecodes:
for b in typecodes:
if a == b and a not in ["f", "d"]:
continue
try:
array.array(a) == array.array(b)
print('FAIL')
except NotImplementedError:
pass
20 changes: 20 additions & 0 deletions tests/basics/bytearray1.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@
print(b"1" == bytearray([1]))
print(bytearray() == bytearray())

b1 = bytearray([1, 2, 3])
b2 = bytearray([1, 2, 3])
b3 = bytearray([1, 3])
print(b1 == b2)
print(b2 != b3)
print(b1 <= b2)
print(b1 <= b3)
print(b1 < b3)
print(b1 >= b2)
print(b3 >= b2)
print(b3 > b2)
print(b1 != b2)
print(b2 == b3)
print(b1 > b2)
print(b1 > b3)
print(b1 >= b3)
print(b1 < b2)
print(b3 < b2)
print(b3 <= b2)

# comparison with other type should return False
print(bytearray() == 1)

Expand Down
9 changes: 9 additions & 0 deletions tests/cpydiff/module_array_comparison.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
categories: Modules,array
description: Comparison between different typecodes not supported
cause: Code size
workaround: Compare individual elements
"""
import array

array.array("b", [1, 2]) == array.array("i", [1, 2])

0 comments on commit b75690d

Please sign in to comment.