objlist.c 20 KB

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