blob: ca907fd01d6ecea305a7b8988ae5c5f9bffa5bbf [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
Paul Sokolovskyda9f0922014-05-13 08:44:45 +03007 * Copyright (c) 2014 Paul Sokolovsky
Damien George04b91472014-05-03 23:27:38 +01008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
Paul Sokolovsky427905c2014-01-18 19:24:47 +020028#include <string.h>
Paul Sokolovsky427905c2014-01-18 19:24:47 +020029#include <assert.h>
30
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030031#include "mpconfig.h"
Paul Sokolovsky427905c2014-01-18 19:24:47 +020032#include "nlr.h"
33#include "misc.h"
Damien George55baff42014-01-21 21:40:13 +000034#include "qstr.h"
Paul Sokolovsky427905c2014-01-18 19:24:47 +020035#include "obj.h"
Paul Sokolovsky427905c2014-01-18 19:24:47 +020036#include "runtime0.h"
37#include "runtime.h"
Paul Sokolovskyc2033242014-02-14 20:21:50 +020038#include "binary.h"
Paul Sokolovsky427905c2014-01-18 19:24:47 +020039
Paul Sokolovskycb78f862014-06-27 20:39:09 +030040#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
41
Paul Sokolovsky427905c2014-01-18 19:24:47 +020042typedef struct _mp_obj_array_t {
43 mp_obj_base_t base;
Damien George40f3c022014-07-03 13:25:24 +010044 mp_uint_t typecode : 8;
Damien George51047752014-02-26 17:40:52 +000045 // free is number of unused elements after len used elements
46 // alloc size = len + free
Damien George40f3c022014-07-03 13:25:24 +010047 mp_uint_t free : (8 * sizeof(mp_uint_t) - 8);
48 mp_uint_t len; // in elements
Paul Sokolovsky427905c2014-01-18 19:24:47 +020049 void *items;
50} mp_obj_array_t;
51
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020052STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
53STATIC mp_obj_array_t *array_new(char typecode, uint n);
54STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
Paul Sokolovsky427905c2014-01-18 19:24:47 +020055
56/******************************************************************************/
57/* array */
58
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020059STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
Paul Sokolovsky427905c2014-01-18 19:24:47 +020060 mp_obj_array_t *o = o_in;
61 if (o->typecode == BYTEARRAY_TYPECODE) {
Paul Sokolovsky18014212014-01-28 03:40:48 +020062 print(env, "bytearray(b", o->typecode);
Paul Sokolovsky2ec38a12014-06-13 21:23:00 +030063 mp_str_print_quoted(print, env, o->items, o->len, true);
Paul Sokolovsky427905c2014-01-18 19:24:47 +020064 } else {
Paul Sokolovsky7e652af2014-01-28 03:14:20 +020065 print(env, "array('%c'", o->typecode);
Paul Sokolovsky18014212014-01-28 03:40:48 +020066 if (o->len > 0) {
Damien George32ca1642014-04-18 22:04:06 +010067 print(env, ", [");
Paul Sokolovsky18014212014-01-28 03:40:48 +020068 for (int i = 0; i < o->len; i++) {
69 if (i > 0) {
70 print(env, ", ");
71 }
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030072 mp_obj_print_helper(print, env, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
Paul Sokolovsky7e652af2014-01-28 03:14:20 +020073 }
Paul Sokolovsky18014212014-01-28 03:40:48 +020074 print(env, "]");
Paul Sokolovsky427905c2014-01-18 19:24:47 +020075 }
Paul Sokolovsky427905c2014-01-18 19:24:47 +020076 }
Paul Sokolovsky7e652af2014-01-28 03:14:20 +020077 print(env, ")");
Paul Sokolovsky427905c2014-01-18 19:24:47 +020078}
79
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020080STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
Paul Sokolovsky427905c2014-01-18 19:24:47 +020081 uint len;
82 // Try to create array of exact len if initializer len is known
83 mp_obj_t len_in = mp_obj_len_maybe(initializer);
84 if (len_in == MP_OBJ_NULL) {
85 len = 0;
86 } else {
87 len = MP_OBJ_SMALL_INT_VALUE(len_in);
88 }
89
90 mp_obj_array_t *array = array_new(typecode, len);
91
Damien Georged17926d2014-03-30 13:35:08 +010092 mp_obj_t iterable = mp_getiter(initializer);
Paul Sokolovsky427905c2014-01-18 19:24:47 +020093 mp_obj_t item;
94 int i = 0;
Damien Georgeea8d06c2014-04-17 23:19:36 +010095 while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
Paul Sokolovsky427905c2014-01-18 19:24:47 +020096 if (len == 0) {
97 array_append(array, item);
98 } else {
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030099 mp_binary_set_val_array(typecode, array->items, i++, item);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200100 }
101 }
102
103 return array;
104}
105
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200106STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien Georgea3f94e02014-04-20 00:13:22 +0100107 mp_arg_check_num(n_args, n_kw, 1, 2, false);
Damien George32ca1642014-04-18 22:04:06 +0100108
109 // get typecode
Paul Sokolovsky11973b42014-01-28 02:31:52 +0200110 uint l;
Damien George698ec212014-02-08 18:17:23 +0000111 const char *typecode = mp_obj_str_get_data(args[0], &l);
Paul Sokolovsky11973b42014-01-28 02:31:52 +0200112
Damien George32ca1642014-04-18 22:04:06 +0100113 if (n_args == 1) {
114 // 1 arg: make an empty array
115 return array_new(*typecode, 0);
116 } else {
117 // 2 args: construct the array from the given iterator
118 return array_construct(*typecode, args[1]);
119 }
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200120}
121
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300122STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien Georgea3f94e02014-04-20 00:13:22 +0100123 mp_arg_check_num(n_args, n_kw, 0, 1, false);
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300124
Damien George32ca1642014-04-18 22:04:06 +0100125 if (n_args == 0) {
126 // no args: construct an empty bytearray
127 return array_new(BYTEARRAY_TYPECODE, 0);
128 } else if (MP_OBJ_IS_SMALL_INT(args[0])) {
129 // 1 arg, an integer: construct a blank bytearray of that length
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300130 uint len = MP_OBJ_SMALL_INT_VALUE(args[0]);
Paul Sokolovskyb9cf3d32014-04-08 04:42:44 +0300131 mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
132 memset(o->items, 0, len);
133 return o;
Damien George32ca1642014-04-18 22:04:06 +0100134 } else {
135 // 1 arg, an iterator: construct the bytearray from that
136 return array_construct(BYTEARRAY_TYPECODE, args[0]);
Paul Sokolovskyb9cf3d32014-04-08 04:42:44 +0300137 }
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200138}
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200139
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200140STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
Paul Sokolovskyc1d9bbc2014-01-30 04:37:19 +0200141 mp_obj_array_t *o = o_in;
142 switch (op) {
Damien Georged17926d2014-03-30 13:35:08 +0100143 case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
144 case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
Damien George6ac5dce2014-05-21 19:42:43 +0100145 default: return MP_OBJ_NULL; // op not supported
Paul Sokolovskyc1d9bbc2014-01-30 04:37:19 +0200146 }
147}
148
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200149STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300150 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200151 mp_obj_array_t *self = self_in;
152 if (self->free == 0) {
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300153 int item_sz = mp_binary_get_size('@', self->typecode, NULL);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200154 // TODO: alloc policy
155 self->free = 8;
156 self->items = m_realloc(self->items, item_sz * self->len, item_sz * (self->len + self->free));
Paul Sokolovskya2240672014-04-28 00:16:57 +0300157 mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200158 }
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300159 mp_binary_set_val_array(self->typecode, self->items, self->len++, arg);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200160 self->free--;
161 return mp_const_none; // return None, as per CPython
162}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200163STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200164
Damien George729f7b42014-04-17 22:10:53 +0100165STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
Damien Georgef4c9b332014-04-08 21:32:29 +0100166 if (value == MP_OBJ_NULL) {
Damien George32ca1642014-04-18 22:04:06 +0100167 // delete item
168 // TODO implement
Paul Sokolovsky26905252014-04-20 20:58:33 +0300169 // TODO: confirmed that both bytearray and array.array support
170 // slice deletion
Damien George6ac5dce2014-05-21 19:42:43 +0100171 return MP_OBJ_NULL; // op not supported
Damien George729f7b42014-04-17 22:10:53 +0100172 } else {
173 mp_obj_array_t *o = self_in;
Damien Georgec49ddb92014-06-01 13:49:35 +0100174 if (0) {
175#if MICROPY_PY_BUILTINS_SLICE
176 } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
Paul Sokolovsky26905252014-04-20 20:58:33 +0300177 if (value != MP_OBJ_SENTINEL) {
178 // Only getting a slice is suported so far, not assignment
179 // TODO: confirmed that both bytearray and array.array support
180 // slice assignment (incl. of different size)
Damien George6ac5dce2014-05-21 19:42:43 +0100181 return MP_OBJ_NULL; // op not supported
Paul Sokolovsky26905252014-04-20 20:58:33 +0300182 }
Paul Sokolovskyde4b9322014-05-25 21:21:57 +0300183 mp_bound_slice_t slice;
184 if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
Paul Sokolovsky5fd5af92014-05-25 22:12:56 +0300185 nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
Damien George11de8392014-06-05 18:57:38 +0100186 "only slices with step=1 (aka None) are supported"));
Paul Sokolovskyd6e12722014-04-19 20:06:57 +0300187 }
Paul Sokolovskyde4b9322014-05-25 21:21:57 +0300188 mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start);
Paul Sokolovskyd6e12722014-04-19 20:06:57 +0300189 int sz = mp_binary_get_size('@', o->typecode, NULL);
190 assert(sz > 0);
191 byte *p = o->items;
Paul Sokolovskyde4b9322014-05-25 21:21:57 +0300192 memcpy(res->items, p + slice.start * sz, (slice.stop - slice.start) * sz);
Paul Sokolovskyd6e12722014-04-19 20:06:57 +0300193 return res;
Damien Georgec49ddb92014-06-01 13:49:35 +0100194#endif
Damien George729f7b42014-04-17 22:10:53 +0100195 } else {
Paul Sokolovskyd6e12722014-04-19 20:06:57 +0300196 uint index = mp_get_index(o->base.type, o->len, index_in, false);
197 if (value == MP_OBJ_SENTINEL) {
198 // load
199 return mp_binary_get_val_array(o->typecode, o->items, index);
200 } else {
201 // store
202 mp_binary_set_val_array(o->typecode, o->items, index, value);
203 return mp_const_none;
204 }
Damien George729f7b42014-04-17 22:10:53 +0100205 }
Damien Georgef4c9b332014-04-08 21:32:29 +0100206 }
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200207}
208
Damien George40f3c022014-07-03 13:25:24 +0100209STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200210 mp_obj_array_t *o = o_in;
211 bufinfo->buf = o->items;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300212 bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
Damien George57a4b4f2014-04-18 22:29:21 +0100213 bufinfo->typecode = o->typecode;
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200214 return 0;
215}
216
Damien George9b196cd2014-03-26 21:47:19 +0000217STATIC const mp_map_elem_t array_locals_dict_table[] = {
218 { MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200219};
220
Damien George9b196cd2014-03-26 21:47:19 +0000221STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
222
Damien Georgecaac5422014-03-25 14:18:18 +0000223const mp_obj_type_t mp_type_array = {
Damien Georgec5966122014-02-15 16:10:44 +0000224 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000225 .name = MP_QSTR_array,
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200226 .print = array_print,
227 .make_new = array_make_new,
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200228 .getiter = array_iterator_new,
Paul Sokolovskyc1d9bbc2014-01-30 04:37:19 +0200229 .unary_op = array_unary_op,
Damien George729f7b42014-04-17 22:10:53 +0100230 .subscr = array_subscr,
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200231 .buffer_p = { .get_buffer = array_get_buffer },
Damien George9b196cd2014-03-26 21:47:19 +0000232 .locals_dict = (mp_obj_t)&array_locals_dict,
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200233};
234
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300235const mp_obj_type_t mp_type_bytearray = {
236 { &mp_type_type },
237 .name = MP_QSTR_bytearray,
238 .print = array_print,
239 .make_new = bytearray_make_new,
240 .getiter = array_iterator_new,
241 .unary_op = array_unary_op,
Damien George729f7b42014-04-17 22:10:53 +0100242 .subscr = array_subscr,
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300243 .buffer_p = { .get_buffer = array_get_buffer },
244 .locals_dict = (mp_obj_t)&array_locals_dict,
245};
246
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200247STATIC mp_obj_array_t *array_new(char typecode, uint n) {
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300248 int typecode_size = mp_binary_get_size('@', typecode, NULL);
Damien George32ca1642014-04-18 22:04:06 +0100249 if (typecode_size <= 0) {
250 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
251 }
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200252 mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
Paul Sokolovsky4dcb6052014-04-08 22:09:14 +0300253 o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200254 o->typecode = typecode;
255 o->free = 0;
256 o->len = n;
Damien George32ca1642014-04-18 22:04:06 +0100257 o->items = m_malloc(typecode_size * o->len);
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200258 return o;
259}
260
Paul Sokolovsky33996682014-01-21 23:30:10 +0200261uint mp_obj_array_len(mp_obj_t self_in) {
262 return ((mp_obj_array_t *)self_in)->len;
263}
264
Paul Sokolovsky427905c2014-01-18 19:24:47 +0200265mp_obj_t mp_obj_new_bytearray(uint n, void *items) {
266 mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
267 memcpy(o->items, items, n);
268 return o;
269}
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200270
Paul Sokolovsky7f11c792014-01-29 00:21:41 +0200271// Create bytearray which references specified memory area
272mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
273 mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
Damien Georgecaac5422014-03-25 14:18:18 +0000274 o->base.type = &mp_type_array;
Paul Sokolovsky7f11c792014-01-29 00:21:41 +0200275 o->typecode = BYTEARRAY_TYPECODE;
276 o->free = 0;
277 o->len = n;
278 o->items = items;
279 return o;
280}
281
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200282/******************************************************************************/
283/* array iterator */
284
285typedef struct _mp_obj_array_it_t {
286 mp_obj_base_t base;
287 mp_obj_array_t *array;
Damien George40f3c022014-07-03 13:25:24 +0100288 mp_uint_t cur;
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200289} mp_obj_array_it_t;
290
Damien Georgecaac5422014-03-25 14:18:18 +0000291STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200292 mp_obj_array_it_t *self = self_in;
293 if (self->cur < self->array->len) {
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300294 return mp_binary_get_val_array(self->array->typecode, self->array->items, self->cur++);
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200295 } else {
Damien Georgeea8d06c2014-04-17 23:19:36 +0100296 return MP_OBJ_STOP_ITERATION;
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200297 }
298}
299
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200300STATIC const mp_obj_type_t array_it_type = {
Damien Georgec5966122014-02-15 16:10:44 +0000301 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000302 .name = MP_QSTR_iterator,
Paul Sokolovskyf7eaf602014-03-30 22:00:12 +0300303 .getiter = mp_identity,
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200304 .iternext = array_it_iternext,
305};
306
Damien Georgecaac5422014-03-25 14:18:18 +0000307STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
Paul Sokolovsky09ce0592014-01-21 23:45:19 +0200308 mp_obj_array_t *array = array_in;
309 mp_obj_array_it_t *o = m_new_obj(mp_obj_array_it_t);
310 o->base.type = &array_it_type;
311 o->array = array;
312 o->cur = 0;
313 return o;
314}
Paul Sokolovskycb78f862014-06-27 20:39:09 +0300315
316#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY