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 : 221951 : static mp_obj_t range_it_iternext(mp_obj_t o_in) {
42 : 221951 : mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in);
43 [ + + + + : 221951 : if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) {
+ + + + ]
44 : 220784 : mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur);
45 : 220784 : o->cur += o->step;
46 : 220784 : 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 : 132 : static void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
80 : 132 : (void)kind;
81 : 132 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
82 : 132 : mp_printf(print, "range(" INT_FMT ", " INT_FMT "", self->start, self->stop);
83 [ + + ]: 132 : if (self->step == 1) {
84 : 56 : mp_print_str(print, ")");
85 : : } else {
86 : 76 : mp_printf(print, ", " INT_FMT ")", self->step);
87 : : }
88 : 132 : }
89 : :
90 : 1583 : 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 : 1583 : mp_arg_check_num(n_args, n_kw, 1, 3, false);
92 : :
93 : 1555 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, type);
94 : 1555 : o->start = 0;
95 : 1555 : o->step = 1;
96 : :
97 [ + + ]: 1555 : if (n_args == 1) {
98 : 1004 : o->stop = mp_obj_get_int(args[0]);
99 : : } else {
100 : 551 : o->start = mp_obj_get_int(args[0]);
101 : 551 : o->stop = mp_obj_get_int(args[1]);
102 [ + + ]: 551 : if (n_args == 3) {
103 : 466 : o->step = mp_obj_get_int(args[2]);
104 [ + + ]: 462 : if (o->step == 0) {
105 : 8 : mp_raise_ValueError(MP_ERROR_TEXT("zero step"));
106 : : }
107 : : }
108 : : }
109 : :
110 : 1539 : return MP_OBJ_FROM_PTR(o);
111 : : }
112 : :
113 : 380 : 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 : 380 : mp_int_t len = self->stop - self->start + self->step;
116 [ + + ]: 380 : if (self->step > 0) {
117 : 324 : len -= 1;
118 : : } else {
119 : 56 : len += 1;
120 : : }
121 : 380 : len = len / self->step;
122 [ + + ]: 380 : if (len < 0) {
123 : 48 : len = 0;
124 : : }
125 : 380 : 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 : 160 : static mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
160 [ + + ]: 160 : if (value == MP_OBJ_SENTINEL) {
161 : : // load
162 : 156 : mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in);
163 : 156 : mp_int_t len = range_len(self);
164 : : #if MICROPY_PY_BUILTINS_SLICE
165 [ - + - + : 156 : if (mp_obj_is_type(index, &mp_type_slice)) {
- + - + +
+ + - ]
166 : 128 : mp_bound_slice_t slice;
167 : 128 : mp_obj_slice_indices(index, len, &slice);
168 : 128 : mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, &mp_type_range);
169 : 128 : o->start = self->start + slice.start * self->step;
170 : 128 : o->stop = self->start + slice.stop * self->step;
171 : 128 : o->step = slice.step * self->step;
172 : 128 : return MP_OBJ_FROM_PTR(o);
173 : : }
174 : : #endif
175 : 28 : size_t index_val = mp_get_index(self->base.type, len, index, false);
176 : 28 : return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);
177 : : } else {
178 : : return MP_OBJ_NULL; // op not supported
179 : : }
180 : : }
181 : :
182 : 1219 : static mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
183 : 1219 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
184 : 1219 : return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf);
185 : : }
186 : :
187 : :
188 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
189 : 28 : static void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) {
190 [ + + ]: 28 : if (dest[0] != MP_OBJ_NULL) {
191 : : // not load attribute
192 : : return;
193 : : }
194 : 24 : mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in);
195 [ + + ]: 24 : if (attr == MP_QSTR_start) {
196 : 8 : dest[0] = mp_obj_new_int(o->start);
197 [ + + ]: 16 : } else if (attr == MP_QSTR_stop) {
198 : 4 : dest[0] = mp_obj_new_int(o->stop);
199 [ + + ]: 12 : } else if (attr == MP_QSTR_step) {
200 : 4 : dest[0] = mp_obj_new_int(o->step);
201 : : }
202 : : }
203 : : #endif
204 : :
205 : : #if MICROPY_PY_BUILTINS_RANGE_BINOP
206 : : #define RANGE_TYPE_BINOP binary_op, range_binary_op,
207 : : #else
208 : : #define RANGE_TYPE_BINOP
209 : : #endif
210 : :
211 : : #if MICROPY_PY_BUILTINS_RANGE_ATTRS
212 : : #define RANGE_TYPE_ATTR attr, range_attr,
213 : : #else
214 : : #define RANGE_TYPE_ATTR
215 : : #endif
216 : :
217 : : MP_DEFINE_CONST_OBJ_TYPE(
218 : : mp_type_range,
219 : : MP_QSTR_range,
220 : : MP_TYPE_FLAG_NONE,
221 : : make_new, range_make_new,
222 : : RANGE_TYPE_BINOP
223 : : RANGE_TYPE_ATTR
224 : : print, range_print,
225 : : unary_op, range_unary_op,
226 : : subscr, range_subscr,
227 : : iter, range_getiter
228 : : );
|