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 : : mp_int_t cur;
37 : : mp_int_t stop;
38 : : mp_int_t step;
39 : : } mp_obj_range_it_t;
40 : :
41 : 221990 : static mp_obj_t range_it_iternext(mp_obj_t o_in) {
42 : 221990 : mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in);
43 [ + + + + : 221990 : if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) {
+ + + + ]
44 : 220823 : mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur);
45 : 220823 : o->cur += o->step;
46 : 220823 : return o_out;
47 : : } else {
48 : : return MP_OBJ_STOP_ITERATION;
49 : : }
50 : : }
51 : :
52 : : static MP_DEFINE_CONST_OBJ_TYPE(
53 : : mp_type_range_it,
54 : : MP_QSTR_iterator,
55 : : MP_TYPE_FLAG_ITER_IS_ITERNEXT,
56 : : iter, range_it_iternext
57 : : );
58 : :
59 : 1219 : 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) {
60 : 1219 : assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t));
61 : 1219 : mp_obj_range_it_t *o = (mp_obj_range_it_t *)iter_buf;
62 : 1219 : o->base.type = &mp_type_range_it;
63 : 1219 : o->cur = cur;
64 : 1219 : o->stop = stop;
65 : 1219 : o->step = step;
66 : 1219 : return MP_OBJ_FROM_PTR(o);
67 : : }
68 : :
69 : : /******************************************************************************/
70 : : /* range */
71 : :
72 : : typedef struct _mp_obj_range_t {
73 : : mp_obj_base_t base;
74 : : mp_int_t start;
75 : : mp_int_t stop;
76 : : mp_int_t step;
77 : : } mp_obj_range_t;
78 : :
79 : 68 : static void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
80 : 68 : (void)kind;
81 : 68 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
82 : 68 : mp_printf(print, "range(" INT_FMT ", " INT_FMT "", self->start, self->stop);
83 [ + + ]: 68 : if (self->step == 1) {
84 : 40 : mp_print_str(print, ")");
85 : : } else {
86 : 28 : mp_printf(print, ", " INT_FMT ")", self->step);
87 : : }
88 : 68 : }
89 : :
90 : 1519 : 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) {
91 : 1519 : mp_arg_check_num(n_args, n_kw, 1, 3, false);
92 : :
93 : 1491 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, type);
94 : 1491 : o->start = 0;
95 : 1491 : o->step = 1;
96 : :
97 [ + + ]: 1491 : if (n_args == 1) {
98 : 1004 : o->stop = mp_obj_get_int(args[0]);
99 : : } else {
100 : 487 : o->start = mp_obj_get_int(args[0]);
101 : 487 : o->stop = mp_obj_get_int(args[1]);
102 [ + + ]: 487 : if (n_args == 3) {
103 : 418 : o->step = mp_obj_get_int(args[2]);
104 [ + + ]: 414 : if (o->step == 0) {
105 : 8 : mp_raise_ValueError(MP_ERROR_TEXT("zero step"));
106 : : }
107 : : }
108 : : }
109 : :
110 : 1475 : return MP_OBJ_FROM_PTR(o);
111 : : }
112 : :
113 : 316 : static mp_int_t range_len(mp_obj_range_t *self) {
114 : : // When computing length, need to take into account step!=1 and step<0.
115 : 316 : mp_int_t len = self->stop - self->start + self->step;
116 [ + + ]: 316 : if (self->step > 0) {
117 : 284 : len -= 1;
118 : : } else {
119 : 32 : len += 1;
120 : : }
121 : 316 : len = len / self->step;
122 [ + + ]: 316 : if (len < 0) {
123 : 16 : len = 0;
124 : : }
125 : 316 : return len;
126 : : }
127 : :
128 : 120 : static mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
129 : 120 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
130 : 120 : mp_int_t len = range_len(self);
131 [ + + + ]: 120 : switch (op) {
132 : 8 : case MP_UNARY_OP_BOOL:
133 [ + + ]: 8 : return mp_obj_new_bool(len > 0);
134 : 108 : case MP_UNARY_OP_LEN:
135 : 108 : return MP_OBJ_NEW_SMALL_INT(len);
136 : : default:
137 : : return MP_OBJ_NULL; // op not supported
138 : : }
139 : : }
140 : :
141 : : #if MICROPY_PY_BUILTINS_RANGE_BINOP
142 : 58 : static mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
143 [ + + + - : 58 : if (!mp_obj_is_type(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) {
+ - ]
144 : : return MP_OBJ_NULL; // op not supported
145 : : }
146 : 52 : mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in);
147 : 52 : mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in);
148 : 52 : mp_int_t lhs_len = range_len(lhs);
149 : 52 : mp_int_t rhs_len = range_len(rhs);
150 : 8 : return mp_obj_new_bool(
151 : : lhs_len == rhs_len
152 [ + + + + ]: 52 : && (lhs_len == 0
153 [ + - ]: 32 : || (lhs->start == rhs->start
154 [ + + - + ]: 32 : && (lhs_len == 1 || lhs->step == rhs->step)))
155 : : );
156 : : }
157 : : #endif
158 : :
159 : 96 : static mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
160 [ + + ]: 96 : if (value == MP_OBJ_SENTINEL) {
161 : : // load
162 : 92 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
163 : 92 : mp_int_t len = range_len(self);
164 : : #if MICROPY_PY_BUILTINS_SLICE
165 [ - + - + : 92 : if (mp_obj_is_type(index, &mp_type_slice)) {
- + - + +
+ + - ]
166 : 64 : mp_bound_slice_t slice;
167 : 64 : mp_seq_get_fast_slice_indexes(len, index, &slice);
168 : 64 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, &mp_type_range);
169 : 64 : o->start = self->start + slice.start * self->step;
170 : 64 : o->stop = self->start + slice.stop * self->step;
171 : 64 : o->step = slice.step * self->step;
172 [ + + ]: 64 : if (slice.step < 0) {
173 : : // Negative slice steps have inclusive stop, so adjust for exclusive
174 : 8 : o->stop -= self->step;
175 : : }
176 : 64 : return MP_OBJ_FROM_PTR(o);
177 : : }
178 : : #endif
179 : 28 : size_t index_val = mp_get_index(self->base.type, len, index, false);
180 : 28 : return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);
181 : : } else {
182 : : return MP_OBJ_NULL; // op not supported
183 : : }
184 : : }
185 : :
186 : 1219 : static mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
187 : 1219 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
188 : 1219 : return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf);
189 : : }
190 : :
191 : :
192 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
193 : 28 : static void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
194 [ + + ]: 28 : if (dest[0] != MP_OBJ_NULL) {
195 : : // not load attribute
196 : : return;
197 : : }
198 : 24 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
199 [ + + ]: 24 : if (attr == MP_QSTR_start) {
200 : 8 : dest[0] = mp_obj_new_int(o->start);
201 [ + + ]: 16 : } else if (attr == MP_QSTR_stop) {
202 : 4 : dest[0] = mp_obj_new_int(o->stop);
203 [ + + ]: 12 : } else if (attr == MP_QSTR_step) {
204 : 4 : dest[0] = mp_obj_new_int(o->step);
205 : : }
206 : : }
207 : : #endif
208 : :
209 : : #if MICROPY_PY_BUILTINS_RANGE_BINOP
210 : : #define RANGE_TYPE_BINOP binary_op, range_binary_op,
211 : : #else
212 : : #define RANGE_TYPE_BINOP
213 : : #endif
214 : :
215 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
216 : : #define RANGE_TYPE_ATTR attr, range_attr,
217 : : #else
218 : : #define RANGE_TYPE_ATTR
219 : : #endif
220 : :
221 : : MP_DEFINE_CONST_OBJ_TYPE(
222 : : mp_type_range,
223 : : MP_QSTR_range,
224 : : MP_TYPE_FLAG_NONE,
225 : : make_new, range_make_new,
226 : : RANGE_TYPE_BINOP
227 : : RANGE_TYPE_ATTR
228 : : print, range_print,
229 : : unary_op, range_unary_op,
230 : : subscr, range_subscr,
231 : : iter, range_getiter
232 : : );
|