Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <stdlib.h>
28 : :
29 : : #include "py/runtime.h"
30 : :
31 : : /******************************************************************************/
32 : : /* range iterator */
33 : :
34 : : typedef struct _mp_obj_range_it_t {
35 : : mp_obj_base_t base;
36 : : // TODO make these values generic objects or something
37 : : mp_int_t cur;
38 : : mp_int_t stop;
39 : : mp_int_t step;
40 : : } mp_obj_range_it_t;
41 : :
42 : 221466 : STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) {
43 : 221466 : mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in);
44 [ + + + + : 221466 : if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) {
+ + + + ]
45 : 220301 : mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur);
46 : 220301 : o->cur += o->step;
47 : 220301 : return o_out;
48 : : } else {
49 : : return MP_OBJ_STOP_ITERATION;
50 : : }
51 : : }
52 : :
53 : : STATIC MP_DEFINE_CONST_OBJ_TYPE(
54 : : mp_type_range_it,
55 : : MP_QSTR_iterator,
56 : : MP_TYPE_FLAG_ITER_IS_ITERNEXT,
57 : : iter, range_it_iternext
58 : : );
59 : :
60 : 1215 : STATIC mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t step, mp_obj_iter_buf_t *iter_buf) {
61 : 1215 : assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t));
62 : 1215 : mp_obj_range_it_t *o = (mp_obj_range_it_t *)iter_buf;
63 : 1215 : o->base.type = &mp_type_range_it;
64 : 1215 : o->cur = cur;
65 : 1215 : o->stop = stop;
66 : 1215 : o->step = step;
67 : 1215 : return MP_OBJ_FROM_PTR(o);
68 : : }
69 : :
70 : : /******************************************************************************/
71 : : /* range */
72 : :
73 : : typedef struct _mp_obj_range_t {
74 : : mp_obj_base_t base;
75 : : // TODO make these values generic objects or something
76 : : mp_int_t start;
77 : : mp_int_t stop;
78 : : mp_int_t step;
79 : : } mp_obj_range_t;
80 : :
81 : 68 : STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
82 : 68 : (void)kind;
83 : 68 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
84 : 68 : mp_printf(print, "range(" INT_FMT ", " INT_FMT "", self->start, self->stop);
85 [ + + ]: 68 : if (self->step == 1) {
86 : 40 : mp_print_str(print, ")");
87 : : } else {
88 : 28 : mp_printf(print, ", " INT_FMT ")", self->step);
89 : : }
90 : 68 : }
91 : :
92 : 1515 : STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
93 : 1515 : mp_arg_check_num(n_args, n_kw, 1, 3, false);
94 : :
95 : 1487 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, type);
96 : 1487 : o->start = 0;
97 : 1487 : o->step = 1;
98 : :
99 [ + + ]: 1487 : if (n_args == 1) {
100 : 1002 : o->stop = mp_obj_get_int(args[0]);
101 : : } else {
102 : 485 : o->start = mp_obj_get_int(args[0]);
103 : 485 : o->stop = mp_obj_get_int(args[1]);
104 [ + + ]: 485 : if (n_args == 3) {
105 : 418 : o->step = mp_obj_get_int(args[2]);
106 [ + + ]: 414 : if (o->step == 0) {
107 : 8 : mp_raise_ValueError(MP_ERROR_TEXT("zero step"));
108 : : }
109 : : }
110 : : }
111 : :
112 : 1471 : return MP_OBJ_FROM_PTR(o);
113 : : }
114 : :
115 : 316 : STATIC mp_int_t range_len(mp_obj_range_t *self) {
116 : : // When computing length, need to take into account step!=1 and step<0.
117 : 316 : mp_int_t len = self->stop - self->start + self->step;
118 [ + + ]: 316 : if (self->step > 0) {
119 : 284 : len -= 1;
120 : : } else {
121 : 32 : len += 1;
122 : : }
123 : 316 : len = len / self->step;
124 [ + + ]: 316 : if (len < 0) {
125 : 16 : len = 0;
126 : : }
127 : 316 : return len;
128 : : }
129 : :
130 : 120 : STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
131 : 120 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
132 : 120 : mp_int_t len = range_len(self);
133 [ + + + ]: 120 : switch (op) {
134 : 8 : case MP_UNARY_OP_BOOL:
135 [ + + ]: 8 : return mp_obj_new_bool(len > 0);
136 : 108 : case MP_UNARY_OP_LEN:
137 : 108 : return MP_OBJ_NEW_SMALL_INT(len);
138 : : default:
139 : : return MP_OBJ_NULL; // op not supported
140 : : }
141 : : }
142 : :
143 : : #if MICROPY_PY_BUILTINS_RANGE_BINOP
144 : 56 : STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
145 [ + + + - : 56 : if (!mp_obj_is_type(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) {
+ - ]
146 : : return MP_OBJ_NULL; // op not supported
147 : : }
148 : 52 : mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in);
149 : 52 : mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in);
150 : 52 : mp_int_t lhs_len = range_len(lhs);
151 : 52 : mp_int_t rhs_len = range_len(rhs);
152 : 8 : return mp_obj_new_bool(
153 : : lhs_len == rhs_len
154 [ + + + + ]: 52 : && (lhs_len == 0
155 [ + - ]: 32 : || (lhs->start == rhs->start
156 [ + + - + ]: 32 : && (lhs_len == 1 || lhs->step == rhs->step)))
157 : : );
158 : : }
159 : : #endif
160 : :
161 : 96 : STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
162 [ + + ]: 96 : if (value == MP_OBJ_SENTINEL) {
163 : : // load
164 : 92 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
165 : 92 : mp_int_t len = range_len(self);
166 : : #if MICROPY_PY_BUILTINS_SLICE
167 [ - + - + : 92 : if (mp_obj_is_type(index, &mp_type_slice)) {
- + - + +
+ + - ]
168 : 64 : mp_bound_slice_t slice;
169 : 64 : mp_seq_get_fast_slice_indexes(len, index, &slice);
170 : 64 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, &mp_type_range);
171 : 64 : o->start = self->start + slice.start * self->step;
172 : 64 : o->stop = self->start + slice.stop * self->step;
173 : 64 : o->step = slice.step * self->step;
174 [ + + ]: 64 : if (slice.step < 0) {
175 : : // Negative slice steps have inclusive stop, so adjust for exclusive
176 : 8 : o->stop -= self->step;
177 : : }
178 : 64 : return MP_OBJ_FROM_PTR(o);
179 : : }
180 : : #endif
181 : 28 : size_t index_val = mp_get_index(self->base.type, len, index, false);
182 : 28 : return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);
183 : : } else {
184 : : return MP_OBJ_NULL; // op not supported
185 : : }
186 : : }
187 : :
188 : 1215 : STATIC mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
189 : 1215 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
190 : 1215 : return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf);
191 : : }
192 : :
193 : :
194 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
195 : 28 : STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
196 [ + + ]: 28 : if (dest[0] != MP_OBJ_NULL) {
197 : : // not load attribute
198 : : return;
199 : : }
200 : 24 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
201 [ + + ]: 24 : if (attr == MP_QSTR_start) {
202 : 8 : dest[0] = mp_obj_new_int(o->start);
203 [ + + ]: 16 : } else if (attr == MP_QSTR_stop) {
204 : 4 : dest[0] = mp_obj_new_int(o->stop);
205 [ + + ]: 12 : } else if (attr == MP_QSTR_step) {
206 : 4 : dest[0] = mp_obj_new_int(o->step);
207 : : }
208 : : }
209 : : #endif
210 : :
211 : : #if MICROPY_PY_BUILTINS_RANGE_BINOP
212 : : #define RANGE_TYPE_BINOP binary_op, range_binary_op,
213 : : #else
214 : : #define RANGE_TYPE_BINOP
215 : : #endif
216 : :
217 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
218 : : #define RANGE_TYPE_ATTR attr, range_attr,
219 : : #else
220 : : #define RANGE_TYPE_ATTR
221 : : #endif
222 : :
223 : : MP_DEFINE_CONST_OBJ_TYPE(
224 : : mp_type_range,
225 : : MP_QSTR_range,
226 : : MP_TYPE_FLAG_NONE,
227 : : make_new, range_make_new,
228 : : RANGE_TYPE_BINOP
229 : : RANGE_TYPE_ATTR
230 : : print, range_print,
231 : : unary_op, range_unary_op,
232 : : subscr, range_subscr,
233 : : iter, range_getiter
234 : : );
|