py: Fix mult by negative number of tuple, list, str, bytes.
Multiplication of a tuple, list, str or bytes now yields an empty sequence (instead of crashing). Addresses issue #799 Also added ability to mult bytes on LHS by integer.
This commit is contained in:
parent
9d02780eaf
commit
9b7a8ee8f1
@ -289,7 +289,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_
|
|||||||
// true acts as 0
|
// true acts as 0
|
||||||
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
|
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
|
||||||
} else if (op == MP_BINARY_OP_MULTIPLY) {
|
} else if (op == MP_BINARY_OP_MULTIPLY) {
|
||||||
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
|
||||||
// multiply is commutative for these types, so delegate to them
|
// multiply is commutative for these types, so delegate to them
|
||||||
return mp_binary_op(op, rhs_in, lhs_in);
|
return mp_binary_op(op, rhs_in, lhs_in);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,9 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
|||||||
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
mp_obj_list_t *s = list_new(o->len * n);
|
mp_obj_list_t *s = list_new(o->len * n);
|
||||||
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
||||||
return s;
|
return s;
|
||||||
|
10
py/objstr.c
10
py/objstr.c
@ -290,10 +290,16 @@ mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BINARY_OP_MULTIPLY: {
|
case MP_BINARY_OP_MULTIPLY: {
|
||||||
if (!MP_OBJ_IS_SMALL_INT(rhs_in)) {
|
mp_int_t n;
|
||||||
|
if (!mp_obj_get_int_maybe(rhs_in, &n)) {
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs_in);
|
if (n <= 0) {
|
||||||
|
if (lhs_type == &mp_type_str) {
|
||||||
|
return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
byte *data;
|
byte *data;
|
||||||
mp_obj_t s = mp_obj_str_builder_start(lhs_type, lhs_len * n, &data);
|
mp_obj_t s = mp_obj_str_builder_start(lhs_type, lhs_len * n, &data);
|
||||||
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data);
|
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data);
|
||||||
|
@ -137,10 +137,13 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
case MP_BINARY_OP_MULTIPLY: {
|
case MP_BINARY_OP_MULTIPLY: {
|
||||||
if (!MP_OBJ_IS_SMALL_INT(rhs)) {
|
mp_int_t n;
|
||||||
|
if (!mp_obj_get_int_maybe(rhs, &n)) {
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
int n = MP_OBJ_SMALL_INT_VALUE(rhs);
|
if (n <= 0) {
|
||||||
|
return mp_const_empty_tuple;
|
||||||
|
}
|
||||||
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
|
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
|
||||||
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
|
||||||
return s;
|
return s;
|
||||||
|
12
tests/basics/bytes_mult.py
Normal file
12
tests/basics/bytes_mult.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# basic multiplication
|
||||||
|
print(b'0' * 5)
|
||||||
|
|
||||||
|
# check negative, 0, positive; lhs and rhs multiplication
|
||||||
|
for i in (-4, -2, 0, 2, 4):
|
||||||
|
print(i * b'12')
|
||||||
|
print(b'12' * i)
|
||||||
|
|
||||||
|
# check that we don't modify existing object
|
||||||
|
a = b'123'
|
||||||
|
c = a * 3
|
||||||
|
print(a, c)
|
@ -1,4 +1,12 @@
|
|||||||
|
# basic multiplication
|
||||||
print([0] * 5)
|
print([0] * 5)
|
||||||
|
|
||||||
|
# check negative, 0, positive; lhs and rhs multiplication
|
||||||
|
for i in (-4, -2, 0, 2, 4):
|
||||||
|
print(i * [1, 2])
|
||||||
|
print([1, 2] * i)
|
||||||
|
|
||||||
|
# check that we don't modify existing list
|
||||||
a = [1, 2, 3]
|
a = [1, 2, 3]
|
||||||
c = a * 3
|
c = a * 3
|
||||||
print(c)
|
print(a, c)
|
||||||
|
12
tests/basics/string_mult.py
Normal file
12
tests/basics/string_mult.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# basic multiplication
|
||||||
|
print('0' * 5)
|
||||||
|
|
||||||
|
# check negative, 0, positive; lhs and rhs multiplication
|
||||||
|
for i in (-4, -2, 0, 2, 4):
|
||||||
|
print(i * '12')
|
||||||
|
print('12' * i)
|
||||||
|
|
||||||
|
# check that we don't modify existing object
|
||||||
|
a = '123'
|
||||||
|
c = a * 3
|
||||||
|
print(a, c)
|
@ -1,4 +1,12 @@
|
|||||||
|
# basic multiplication
|
||||||
print((0,) * 5)
|
print((0,) * 5)
|
||||||
|
|
||||||
|
# check negative, 0, positive; lhs and rhs multiplication
|
||||||
|
for i in (-4, -2, 0, 2, 4):
|
||||||
|
print(i * (1, 2))
|
||||||
|
print((1, 2) * i)
|
||||||
|
|
||||||
|
# check that we don't modify existing tuple
|
||||||
a = (1, 2, 3)
|
a = (1, 2, 3)
|
||||||
c = a * 3
|
c = a * 3
|
||||||
print(c)
|
print(a, c)
|
||||||
|
Loading…
Reference in New Issue
Block a user