diff options
author | Damien George <damien.p.george@gmail.com> | 2014-02-02 13:13:29 +0000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-02-02 13:13:29 +0000 |
commit | 09e1f43200ec28082456042a58d9f39f483f3ad0 (patch) | |
tree | a61fff4a0fbad891177d64bf311c9cb0882b4e1b /py | |
parent | cd82e02e84df5f9f2f3082d865beae25217af2a1 (diff) | |
parent | ea2509d92cbb222854ceb0b323b616b807dd221b (diff) | |
download | micropython-09e1f43200ec28082456042a58d9f39f483f3ad0.tar.gz micropython-09e1f43200ec28082456042a58d9f39f483f3ad0.zip |
Merge branch 'master' of github.com:micropython/micropython
Diffstat (limited to 'py')
-rw-r--r-- | py/obj.h | 3 | ||||
-rw-r--r-- | py/objlist.c | 12 | ||||
-rw-r--r-- | py/objstr.c | 34 | ||||
-rw-r--r-- | py/objtuple.c | 13 | ||||
-rw-r--r-- | py/runtime.c | 26 | ||||
-rw-r--r-- | py/sequence.c | 68 |
6 files changed, 130 insertions, 26 deletions
@@ -395,3 +395,6 @@ typedef struct _mp_obj_classmethod_t { // sequence helpers void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); +bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end); +#define m_seq_copy(dest, src, len, item_sz) memcpy(dest, src, len * sizeof(item_sz)) +bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2); diff --git a/py/objlist.c b/py/objlist.c index b28ca81279..59a4ad6b12 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -136,7 +136,17 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case RT_BINARY_OP_SUBSCR: { - // list load +#if MICROPY_ENABLE_SLICE + if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { + machine_uint_t start, stop; + if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) { + assert(0); + } + mp_obj_list_t *res = list_new(stop - start); + m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); + return res; + } +#endif uint index = mp_get_index(o->base.type, o->len, rhs); return o->items[index]; } diff --git a/py/objstr.c b/py/objstr.c index 3f6aa483e2..03602b6ec7 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -115,25 +115,9 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } #if MICROPY_ENABLE_SLICE } else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) { - machine_int_t start, stop, step; - mp_obj_slice_get(rhs_in, &start, &stop, &step); - assert(step == 1); - if (start < 0) { - start = lhs_len + start; - if (start < 0) { - start = 0; - } - } else if (start > lhs_len) { - start = lhs_len; - } - if (stop <= 0) { - stop = lhs_len + stop; - // CPython returns empty string in such case - if (stop < 0) { - stop = start; - } - } else if (stop > lhs_len) { - stop = lhs_len; + machine_uint_t start, stop; + if (!m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)) { + assert(0); } return mp_obj_new_str(lhs_data + start, stop - start, false); #endif @@ -187,6 +171,18 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data); return mp_obj_str_builder_end(s); } + + // These 2 are never passed here, dealt with as a special case in rt_binary_op(). + //case RT_BINARY_OP_EQUAL: + //case RT_BINARY_OP_NOT_EQUAL: + case RT_BINARY_OP_LESS: + case RT_BINARY_OP_LESS_EQUAL: + case RT_BINARY_OP_MORE: + case RT_BINARY_OP_MORE_EQUAL: + if (MP_OBJ_IS_STR(rhs_in)) { + GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); + return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len)); + } } return MP_OBJ_NULL; // op not supported diff --git a/py/objtuple.c b/py/objtuple.c index 5f1744ea30..3e5041c9dd 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -1,3 +1,4 @@ +#include <string.h> #include <stdlib.h> #include <stdint.h> #include <assert.h> @@ -87,7 +88,17 @@ static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case RT_BINARY_OP_SUBSCR: { - // tuple load +#if MICROPY_ENABLE_SLICE + if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { + machine_uint_t start, stop; + if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) { + assert(0); + } + mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL); + m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); + return res; + } +#endif uint index = mp_get_index(o->base.type, o->len, rhs); return o->items[index]; } diff --git a/py/runtime.c b/py/runtime.c index b524e65208..07be34d017 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -768,8 +768,8 @@ mp_obj_t rt_store_set(mp_obj_t set, mp_obj_t item) { // unpacked items are stored in reverse order into the array pointed to by items void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) { + uint seq_len; if (MP_OBJ_IS_TYPE(seq_in, &tuple_type) || MP_OBJ_IS_TYPE(seq_in, &list_type)) { - uint seq_len; mp_obj_t *seq_items; if (MP_OBJ_IS_TYPE(seq_in, &tuple_type)) { mp_obj_tuple_get(seq_in, &seq_len, &seq_items); @@ -777,17 +777,33 @@ void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) { mp_obj_list_get(seq_in, &seq_len, &seq_items); } if (seq_len < num) { - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", (void*)(machine_uint_t)seq_len)); + goto too_short; } else if (seq_len > num) { - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num)); + goto too_long; } for (uint i = 0; i < num; i++) { items[i] = seq_items[num - 1 - i]; } } else { - // TODO call rt_getiter and extract via rt_iternext - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(seq_in))); + mp_obj_t iterable = rt_getiter(seq_in); + + for (seq_len = 0; seq_len < num; seq_len++) { + mp_obj_t el = rt_iternext(iterable); + if (el == mp_const_stop_iteration) { + goto too_short; + } + items[num - 1 - seq_len] = el; + } + if (rt_iternext(iterable) != mp_const_stop_iteration) { + goto too_long; + } } + return; + +too_short: + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", seq_len)); +too_long: + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", num)); } mp_obj_t rt_build_map(int n_args) { diff --git a/py/sequence.c b/py/sequence.c index 56718c6f85..74b4fcfdf8 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -14,6 +14,8 @@ // Helpers for sequence types +#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } + // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) { @@ -23,3 +25,69 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void dest = (char*)dest + copy_sz; } } + +bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) { + machine_int_t start, stop, step; + mp_obj_slice_get(slice, &start, &stop, &step); + if (step != 1) { + return false; + } + + // Unlike subscription, out-of-bounds slice indexes are never error + if (start < 0) { + start = len + start; + if (start < 0) { + start = 0; + } + } else if (start > len) { + start = len; + } + if (stop <= 0) { + stop = len + stop; + // CPython returns empty sequence in such case + if (stop < 0) { + stop = start; + } + } else if (stop > len) { + stop = len; + } + *begin = start; + *end = stop; + return true; +} + +// Special-case comparison function for sequences of bytes +// Don't pass RT_BINARY_OP_NOT_EQUAL here +bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) { + // Let's deal only with > & >= + if (op == RT_BINARY_OP_LESS || op == RT_BINARY_OP_LESS_EQUAL) { + SWAP(const byte*, data1, data2); + SWAP(uint, len1, len2); + if (op == RT_BINARY_OP_LESS) { + op = RT_BINARY_OP_MORE; + } else { + op = RT_BINARY_OP_MORE_EQUAL; + } + } + uint min_len = len1 < len2 ? len1 : len2; + int res = memcmp(data1, data2, min_len); + if (res < 0) { + return false; + } + if (res > 0) { + return true; + } + + // If we had tie in the last element... + // ... and we have lists of different lengths... + if (len1 != len2) { + if (len1 < len2) { + // ... then longer list length wins (we deal only with >) + return false; + } + } else if (op == RT_BINARY_OP_MORE) { + // Otherwise, if we have strict relation, equality means failure + return false; + } + return true; +} |