objlist.c 20 KB

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