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 <string.h> |
28 | #include <assert.h> |
29 | |
30 | #include "py/objlist.h" |
31 | #include "py/runtime.h" |
32 | #include "py/stackctrl.h" |
33 | |
34 | STATIC mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf); |
35 | STATIC mp_obj_list_t *list_new(size_t n); |
36 | STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in); |
37 | STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args); |
38 | |
39 | // TODO: Move to mpconfig.h |
40 | #define LIST_MIN_ALLOC 4 |
41 | |
42 | /******************************************************************************/ |
43 | /* list */ |
44 | |
45 | STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { |
46 | mp_obj_list_t *o = MP_OBJ_TO_PTR(o_in); |
47 | if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { |
48 | kind = PRINT_REPR; |
49 | } |
50 | mp_print_str(print, "[" ); |
51 | for (size_t i = 0; i < o->len; i++) { |
52 | if (i > 0) { |
53 | mp_print_str(print, ", " ); |
54 | } |
55 | mp_obj_print_helper(print, o->items[i], kind); |
56 | } |
57 | mp_print_str(print, "]" ); |
58 | } |
59 | |
60 | STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { |
61 | mp_obj_t iter = mp_getiter(iterable, NULL); |
62 | mp_obj_t item; |
63 | while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { |
64 | mp_obj_list_append(list, item); |
65 | } |
66 | return list; |
67 | } |
68 | |
69 | STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
70 | (void)type_in; |
71 | mp_arg_check_num(n_args, n_kw, 0, 1, false); |
72 | |
73 | switch (n_args) { |
74 | case 0: |
75 | // return a new, empty list |
76 | return mp_obj_new_list(0, NULL); |
77 | |
78 | case 1: |
79 | default: { |
80 | // make list from iterable |
81 | // TODO: optimize list/tuple |
82 | mp_obj_t list = mp_obj_new_list(0, NULL); |
83 | return list_extend_from_iter(list, args[0]); |
84 | } |
85 | } |
86 | } |
87 | |
88 | STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { |
89 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
90 | switch (op) { |
91 | case MP_UNARY_OP_BOOL: |
92 | return mp_obj_new_bool(self->len != 0); |
93 | case MP_UNARY_OP_LEN: |
94 | return MP_OBJ_NEW_SMALL_INT(self->len); |
95 | #if MICROPY_PY_SYS_GETSIZEOF |
96 | case MP_UNARY_OP_SIZEOF: { |
97 | size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; |
98 | return MP_OBJ_NEW_SMALL_INT(sz); |
99 | } |
100 | #endif |
101 | default: |
102 | return MP_OBJ_NULL; // op not supported |
103 | } |
104 | } |
105 | |
106 | STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { |
107 | mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); |
108 | switch (op) { |
109 | case MP_BINARY_OP_ADD: { |
110 | if (!mp_obj_is_type(rhs, &mp_type_list)) { |
111 | return MP_OBJ_NULL; // op not supported |
112 | } |
113 | mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); |
114 | mp_obj_list_t *s = list_new(o->len + p->len); |
115 | mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); |
116 | return MP_OBJ_FROM_PTR(s); |
117 | } |
118 | case MP_BINARY_OP_INPLACE_ADD: { |
119 | list_extend(lhs, rhs); |
120 | return lhs; |
121 | } |
122 | case MP_BINARY_OP_MULTIPLY: { |
123 | mp_int_t n; |
124 | if (!mp_obj_get_int_maybe(rhs, &n)) { |
125 | return MP_OBJ_NULL; // op not supported |
126 | } |
127 | if (n < 0) { |
128 | n = 0; |
129 | } |
130 | mp_obj_list_t *s = list_new(o->len * n); |
131 | mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); |
132 | return MP_OBJ_FROM_PTR(s); |
133 | } |
134 | case MP_BINARY_OP_EQUAL: |
135 | case MP_BINARY_OP_LESS: |
136 | case MP_BINARY_OP_LESS_EQUAL: |
137 | case MP_BINARY_OP_MORE: |
138 | case MP_BINARY_OP_MORE_EQUAL: { |
139 | if (!mp_obj_is_type(rhs, &mp_type_list)) { |
140 | if (op == MP_BINARY_OP_EQUAL) { |
141 | return mp_const_false; |
142 | } |
143 | return MP_OBJ_NULL; // op not supported |
144 | } |
145 | |
146 | mp_obj_list_t *another = MP_OBJ_TO_PTR(rhs); |
147 | bool res = mp_seq_cmp_objs(op, o->items, o->len, another->items, another->len); |
148 | return mp_obj_new_bool(res); |
149 | } |
150 | |
151 | default: |
152 | return MP_OBJ_NULL; // op not supported |
153 | } |
154 | } |
155 | |
156 | STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { |
157 | if (value == MP_OBJ_NULL) { |
158 | // delete |
159 | #if MICROPY_PY_BUILTINS_SLICE |
160 | if (mp_obj_is_type(index, &mp_type_slice)) { |
161 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
162 | mp_bound_slice_t slice; |
163 | if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { |
164 | mp_raise_NotImplementedError(NULL); |
165 | } |
166 | |
167 | mp_int_t len_adj = slice.start - slice.stop; |
168 | assert(len_adj <= 0); |
169 | mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items /*NULL*/, 0, sizeof(*self->items)); |
170 | // Clear "freed" elements at the end of list |
171 | mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); |
172 | self->len += len_adj; |
173 | return mp_const_none; |
174 | } |
175 | #endif |
176 | mp_obj_t args[2] = {self_in, index}; |
177 | list_pop(2, args); |
178 | return mp_const_none; |
179 | } else if (value == MP_OBJ_SENTINEL) { |
180 | // load |
181 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
182 | #if MICROPY_PY_BUILTINS_SLICE |
183 | if (mp_obj_is_type(index, &mp_type_slice)) { |
184 | mp_bound_slice_t slice; |
185 | if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { |
186 | return mp_seq_extract_slice(self->len, self->items, &slice); |
187 | } |
188 | mp_obj_list_t *res = list_new(slice.stop - slice.start); |
189 | mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); |
190 | return MP_OBJ_FROM_PTR(res); |
191 | } |
192 | #endif |
193 | size_t index_val = mp_get_index(self->base.type, self->len, index, false); |
194 | return self->items[index_val]; |
195 | } else { |
196 | #if MICROPY_PY_BUILTINS_SLICE |
197 | if (mp_obj_is_type(index, &mp_type_slice)) { |
198 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
199 | size_t value_len; |
200 | mp_obj_t *value_items; |
201 | mp_obj_get_array(value, &value_len, &value_items); |
202 | mp_bound_slice_t slice_out; |
203 | if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { |
204 | mp_raise_NotImplementedError(NULL); |
205 | } |
206 | mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); |
207 | if (len_adj > 0) { |
208 | if (self->len + len_adj > self->alloc) { |
209 | // TODO: Might optimize memory copies here by checking if block can |
210 | // be grown inplace or not |
211 | self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); |
212 | self->alloc = self->len + len_adj; |
213 | } |
214 | mp_seq_replace_slice_grow_inplace(self->items, self->len, |
215 | slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items)); |
216 | } else { |
217 | mp_seq_replace_slice_no_grow(self->items, self->len, |
218 | slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items)); |
219 | // Clear "freed" elements at the end of list |
220 | mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); |
221 | // TODO: apply allocation policy re: alloc_size |
222 | } |
223 | self->len += len_adj; |
224 | return mp_const_none; |
225 | } |
226 | #endif |
227 | mp_obj_list_store(self_in, index, value); |
228 | return mp_const_none; |
229 | } |
230 | } |
231 | |
232 | STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { |
233 | return mp_obj_new_list_iterator(o_in, 0, iter_buf); |
234 | } |
235 | |
236 | mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { |
237 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
238 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
239 | if (self->len >= self->alloc) { |
240 | self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); |
241 | self->alloc *= 2; |
242 | mp_seq_clear(self->items, self->len + 1, self->alloc, sizeof(*self->items)); |
243 | } |
244 | self->items[self->len++] = arg; |
245 | return mp_const_none; // return None, as per CPython |
246 | } |
247 | |
248 | STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { |
249 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
250 | if (mp_obj_is_type(arg_in, &mp_type_list)) { |
251 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
252 | mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in); |
253 | |
254 | if (self->len + arg->len > self->alloc) { |
255 | // TODO: use alloc policy for "4" |
256 | self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); |
257 | self->alloc = self->len + arg->len + 4; |
258 | mp_seq_clear(self->items, self->len + arg->len, self->alloc, sizeof(*self->items)); |
259 | } |
260 | |
261 | memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len); |
262 | self->len += arg->len; |
263 | } else { |
264 | list_extend_from_iter(self_in, arg_in); |
265 | } |
266 | return mp_const_none; // return None, as per CPython |
267 | } |
268 | |
269 | STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { |
270 | mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); |
271 | mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); |
272 | if (self->len == 0) { |
273 | mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("pop from empty list" )); |
274 | } |
275 | size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); |
276 | mp_obj_t ret = self->items[index]; |
277 | self->len -= 1; |
278 | memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); |
279 | // Clear stale pointer from slot which just got freed to prevent GC issues |
280 | self->items[self->len] = MP_OBJ_NULL; |
281 | if (self->alloc > LIST_MIN_ALLOC && self->alloc > 2 * self->len) { |
282 | self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc / 2); |
283 | self->alloc /= 2; |
284 | } |
285 | return ret; |
286 | } |
287 | |
288 | STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { |
289 | MP_STACK_CHECK(); |
290 | while (head < tail) { |
291 | mp_obj_t *h = head - 1; |
292 | mp_obj_t *t = tail; |
293 | mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn |
294 | for (;;) { |
295 | do {++h; |
296 | } while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result); |
297 | do {--t; |
298 | } while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result); |
299 | if (h >= t) { |
300 | break; |
301 | } |
302 | mp_obj_t x = h[0]; |
303 | h[0] = t[0]; |
304 | t[0] = x; |
305 | } |
306 | mp_obj_t x = h[0]; |
307 | h[0] = tail[0]; |
308 | tail[0] = x; |
309 | // do the smaller recursive call first, to keep stack within O(log(N)) |
310 | if (t - head < tail - h - 1) { |
311 | mp_quicksort(head, t, key_fn, binop_less_result); |
312 | head = h + 1; |
313 | } else { |
314 | mp_quicksort(h + 1, tail, key_fn, binop_less_result); |
315 | tail = t; |
316 | } |
317 | } |
318 | } |
319 | |
320 | // TODO Python defines sort to be stable but ours is not |
321 | mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
322 | static const mp_arg_t allowed_args[] = { |
323 | { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, |
324 | { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, |
325 | }; |
326 | |
327 | // parse args |
328 | struct { |
329 | mp_arg_val_t key, reverse; |
330 | } args; |
331 | mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, |
332 | MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); |
333 | |
334 | mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list)); |
335 | mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); |
336 | |
337 | if (self->len > 1) { |
338 | mp_quicksort(self->items, self->items + self->len - 1, |
339 | args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj, |
340 | args.reverse.u_bool ? mp_const_false : mp_const_true); |
341 | } |
342 | |
343 | return mp_const_none; |
344 | } |
345 | |
346 | STATIC mp_obj_t list_clear(mp_obj_t self_in) { |
347 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
348 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
349 | self->len = 0; |
350 | self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); |
351 | self->alloc = LIST_MIN_ALLOC; |
352 | mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); |
353 | return mp_const_none; |
354 | } |
355 | |
356 | STATIC mp_obj_t list_copy(mp_obj_t self_in) { |
357 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
358 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
359 | return mp_obj_new_list(self->len, self->items); |
360 | } |
361 | |
362 | STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { |
363 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
364 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
365 | return mp_seq_count_obj(self->items, self->len, value); |
366 | } |
367 | |
368 | STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { |
369 | mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); |
370 | mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); |
371 | return mp_seq_index_obj(self->items, self->len, n_args, args); |
372 | } |
373 | |
374 | STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { |
375 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
376 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
377 | // insert has its own strange index logic |
378 | mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); |
379 | if (index < 0) { |
380 | index += self->len; |
381 | } |
382 | if (index < 0) { |
383 | index = 0; |
384 | } |
385 | if ((size_t)index > self->len) { |
386 | index = self->len; |
387 | } |
388 | |
389 | mp_obj_list_append(self_in, mp_const_none); |
390 | |
391 | for (mp_int_t i = self->len - 1; i > index; i--) { |
392 | self->items[i] = self->items[i - 1]; |
393 | } |
394 | self->items[index] = obj; |
395 | |
396 | return mp_const_none; |
397 | } |
398 | |
399 | mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { |
400 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
401 | mp_obj_t args[] = {self_in, value}; |
402 | args[1] = list_index(2, args); |
403 | list_pop(2, args); |
404 | |
405 | return mp_const_none; |
406 | } |
407 | |
408 | STATIC mp_obj_t list_reverse(mp_obj_t self_in) { |
409 | mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); |
410 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
411 | |
412 | mp_int_t len = self->len; |
413 | for (mp_int_t i = 0; i < len / 2; i++) { |
414 | mp_obj_t a = self->items[i]; |
415 | self->items[i] = self->items[len - i - 1]; |
416 | self->items[len - i - 1] = a; |
417 | } |
418 | |
419 | return mp_const_none; |
420 | } |
421 | |
422 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append); |
423 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend); |
424 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear); |
425 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy); |
426 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count); |
427 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index); |
428 | STATIC MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert); |
429 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop); |
430 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, mp_obj_list_remove); |
431 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse); |
432 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 1, mp_obj_list_sort); |
433 | |
434 | STATIC const mp_rom_map_elem_t list_locals_dict_table[] = { |
435 | { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&list_append_obj) }, |
436 | { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&list_clear_obj) }, |
437 | { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&list_copy_obj) }, |
438 | { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&list_count_obj) }, |
439 | { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&list_extend_obj) }, |
440 | { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&list_index_obj) }, |
441 | { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&list_insert_obj) }, |
442 | { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&list_pop_obj) }, |
443 | { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&list_remove_obj) }, |
444 | { MP_ROM_QSTR(MP_QSTR_reverse), MP_ROM_PTR(&list_reverse_obj) }, |
445 | { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&list_sort_obj) }, |
446 | }; |
447 | |
448 | STATIC MP_DEFINE_CONST_DICT(list_locals_dict, list_locals_dict_table); |
449 | |
450 | const mp_obj_type_t mp_type_list = { |
451 | { &mp_type_type }, |
452 | .name = MP_QSTR_list, |
453 | .print = list_print, |
454 | .make_new = list_make_new, |
455 | .unary_op = list_unary_op, |
456 | .binary_op = list_binary_op, |
457 | .subscr = list_subscr, |
458 | .getiter = list_getiter, |
459 | .locals_dict = (mp_obj_dict_t *)&list_locals_dict, |
460 | }; |
461 | |
462 | void mp_obj_list_init(mp_obj_list_t *o, size_t n) { |
463 | o->base.type = &mp_type_list; |
464 | o->alloc = n < LIST_MIN_ALLOC ? LIST_MIN_ALLOC : n; |
465 | o->len = n; |
466 | o->items = m_new(mp_obj_t, o->alloc); |
467 | mp_seq_clear(o->items, n, o->alloc, sizeof(*o->items)); |
468 | } |
469 | |
470 | STATIC mp_obj_list_t *list_new(size_t n) { |
471 | mp_obj_list_t *o = m_new_obj(mp_obj_list_t); |
472 | mp_obj_list_init(o, n); |
473 | return o; |
474 | } |
475 | |
476 | mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { |
477 | mp_obj_list_t *o = list_new(n); |
478 | if (items != NULL) { |
479 | for (size_t i = 0; i < n; i++) { |
480 | o->items[i] = items[i]; |
481 | } |
482 | } |
483 | return MP_OBJ_FROM_PTR(o); |
484 | } |
485 | |
486 | void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { |
487 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
488 | *len = self->len; |
489 | *items = self->items; |
490 | } |
491 | |
492 | void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { |
493 | // trust that the caller knows what it's doing |
494 | // TODO realloc if len got much smaller than alloc |
495 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
496 | self->len = len; |
497 | } |
498 | |
499 | void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { |
500 | mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); |
501 | size_t i = mp_get_index(self->base.type, self->len, index, false); |
502 | self->items[i] = value; |
503 | } |
504 | |
505 | /******************************************************************************/ |
506 | /* list iterator */ |
507 | |
508 | typedef struct _mp_obj_list_it_t { |
509 | mp_obj_base_t base; |
510 | mp_fun_1_t iternext; |
511 | mp_obj_t list; |
512 | size_t cur; |
513 | } mp_obj_list_it_t; |
514 | |
515 | STATIC mp_obj_t list_it_iternext(mp_obj_t self_in) { |
516 | mp_obj_list_it_t *self = MP_OBJ_TO_PTR(self_in); |
517 | mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); |
518 | if (self->cur < list->len) { |
519 | mp_obj_t o_out = list->items[self->cur]; |
520 | self->cur += 1; |
521 | return o_out; |
522 | } else { |
523 | return MP_OBJ_STOP_ITERATION; |
524 | } |
525 | } |
526 | |
527 | mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf) { |
528 | assert(sizeof(mp_obj_list_it_t) <= sizeof(mp_obj_iter_buf_t)); |
529 | mp_obj_list_it_t *o = (mp_obj_list_it_t *)iter_buf; |
530 | o->base.type = &mp_type_polymorph_iter; |
531 | o->iternext = list_it_iternext; |
532 | o->list = list; |
533 | o->cur = cur; |
534 | return MP_OBJ_FROM_PTR(o); |
535 | } |
536 | |