From e0ef7e309256a72a89a9949f93e75b9e0fb2b37f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 24 Feb 2017 15:13:56 +0100 Subject: [PATCH] Add indices() support to slice. --- atmel-samd/mpconfigport.h | 1 + py/objslice.c | 83 +++++++++++++++++++++++++++++++++++ tests/basics/builtin_slice.py | 32 ++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/atmel-samd/mpconfigport.h b/atmel-samd/mpconfigport.h index 667f9bf3fd..1803bdf7b3 100644 --- a/atmel-samd/mpconfigport.h +++ b/atmel-samd/mpconfigport.h @@ -43,6 +43,7 @@ #define MICROPY_PY_BUILTINS_REVERSED (0) #define MICROPY_PY_BUILTINS_SET (1) #define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) #define MICROPY_PY_BUILTINS_MIN_MAX (1) #define MICROPY_PY___FILE__ (1) diff --git a/py/objslice.c b/py/objslice.c index 928be6dab1..6c95926281 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -29,6 +29,7 @@ #include "py/nlr.h" #include "py/obj.h" +#include "py/runtime.h" #include "py/runtime0.h" /******************************************************************************/ @@ -58,6 +59,58 @@ STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t } #if MICROPY_PY_BUILTINS_SLICE_ATTRS +STATIC mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) { + mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + if (!MP_OBJ_IS_SMALL_INT(length_obj)) { + mp_raise_TypeError("Length must be an int"); + } + + int length = MP_OBJ_SMALL_INT_VALUE(length_obj); + if (length < 0) { + mp_raise_ValueError("Length must be non-negative"); + } + + mp_obj_t indices[3] = {MP_OBJ_NEW_SMALL_INT(0), length_obj, MP_OBJ_NEW_SMALL_INT(1)}; + mp_obj_t slice[2] = {self->start, self->stop}; + + int step = 1; + if (self->step != mp_const_none) { + indices[2] = self->step; + step = MP_OBJ_SMALL_INT_VALUE(self->step); + if (step < 0) { + indices[0] = MP_OBJ_NEW_SMALL_INT(length - 1); + indices[1] = MP_OBJ_NEW_SMALL_INT(-1); + } + if (step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } + for (int i = 0; i < 2; i++) { + if (slice[i] == mp_const_none) { + continue; + } + int value = MP_OBJ_SMALL_INT_VALUE(slice[i]); + if (value < 0) { + value += length; + } + if (value < 0) { + if (step > 0) { + value = 0; + } else if (step < 0) { + value = -1; + } + } else if (value > length) { + value = length; + } + indices[i] = MP_OBJ_NEW_SMALL_INT(value); + } + + mp_obj_t tuple = mp_obj_new_tuple(3, indices); + + return tuple; +} +MP_DEFINE_CONST_FUN_OBJ_2(slice_indices_obj, slice_indices); + STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { // not load attribute @@ -70,8 +123,13 @@ STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = self->stop; } else if (attr == MP_QSTR_step) { dest[0] = self->step; + } else if (attr == MP_QSTR_indices) { + mp_convert_member_lookup(self_in, self->base.type, (mp_obj_t) &slice_indices_obj, dest); } } + +STATIC mp_obj_t slice_make_new(const mp_obj_type_t *type, + mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); #endif const mp_obj_type_t mp_type_slice = { @@ -79,6 +137,7 @@ const mp_obj_type_t mp_type_slice = { .name = MP_QSTR_slice, .print = slice_print, #if MICROPY_PY_BUILTINS_SLICE_ATTRS + .make_new = slice_make_new, .attr = slice_attr, #endif }; @@ -92,6 +151,30 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { return MP_OBJ_FROM_PTR(o); } +#if MICROPY_PY_BUILTINS_SLICE_ATTRS +STATIC mp_obj_t slice_make_new(const mp_obj_type_t *type, + mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + // check number of arguments + mp_arg_check_num(n_args, n_kw, 1, 3, false); + + // 1st argument is the pin + mp_obj_t start = mp_const_none; + mp_obj_t stop = mp_const_none; + mp_obj_t step = mp_const_none; + if (n_args == 1) { + stop = args[0]; + } else { + start = args[0]; + stop = args[1]; + if (n_args == 3) { + step = args[2]; + } + } + + return mp_obj_new_slice(start, stop, step); +} +#endif + void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py index df84d5c57b..68a6635b35 100644 --- a/tests/basics/builtin_slice.py +++ b/tests/basics/builtin_slice.py @@ -9,3 +9,35 @@ s = A()[1:2:3] # check type print(type(s) is slice) + +s = slice(10) +print(s) + +s = slice(0, 4) +print(s) + +s = slice(0, 4, 2) +print(s) + +s = slice(-1) +print(s) +print(s.indices(10)) + +s = slice(-5, -1) +print(s) +print(s.indices(10)) + +s = slice(-100, -2, -1) +print(s) +print(s.indices(10)) + +s = slice(None, None, -2) +print(s) +print(s.indices(10)) + +s = slice(-100, -2, 0) +print(s) +try: + print(s.indices(10)) +except Exception as e: + print(e)