objarray.c 20.6 KB
Newer Older
1
2
3
4
5
6
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
7
 * Copyright (c) 2014 Paul Sokolovsky
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

28
29
#include <string.h>
#include <assert.h>
30
#include <stdint.h>
31

32
33
34
35
#include "py/nlr.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/binary.h"
36

37
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// About memoryview object: We want to reuse as much code as possible from
// array, and keep the memoryview object 4 words in size so it fits in 1 GC
// block.  Also, memoryview must keep a pointer to the base of the buffer so
// that the buffer is not GC'd if the original parent object is no longer
// around (we are assuming that all memoryview'able objects return a pointer
// which points to the start of a GC chunk).  Given the above constraints we
// do the following:
//  - typecode high bit is set if the buffer is read-write (else read-only)
//  - free is the offset in elements to the first item in the memoryview
//  - len is the length in elements
//  - items points to the start of the original buffer
// Note that we don't handle the case where the original buffer might change
// size due to a resize of the original parent object.

// make (& TYPECODE_MASK) a null operation if memorview not enabled
#if MICROPY_PY_BUILTINS_MEMORYVIEW
#define TYPECODE_MASK (0x7f)
#else
#define TYPECODE_MASK (~(mp_uint_t)1)
#endif

60
61
typedef struct _mp_obj_array_t {
    mp_obj_base_t base;
62
    mp_uint_t typecode : 8;
63
64
    // free is number of unused elements after len used elements
    // alloc size = len + free
65
66
    mp_uint_t free : (8 * sizeof(mp_uint_t) - 8);
    mp_uint_t len; // in elements
67
68
69
    void *items;
} mp_obj_array_t;

70
71
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
72
STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
73
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
74
75

/******************************************************************************/
76
// array
77

78
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
79
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
80
    (void)kind;
81
82
    mp_obj_array_t *o = o_in;
    if (o->typecode == BYTEARRAY_TYPECODE) {
83
        print(env, "bytearray(b");
84
        mp_str_print_quoted(print, env, o->items, o->len, true);
85
    } else {
86
        print(env, "array('%c'", o->typecode);
87
        if (o->len > 0) {
88
            print(env, ", [");
89
            for (mp_uint_t i = 0; i < o->len; i++) {
90
91
92
                if (i > 0) {
                    print(env, ", ");
                }
93
                mp_obj_print_helper(print, env, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
94
            }
95
            print(env, "]");
96
97
        }
    }
98
    print(env, ")");
99
}
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#endif

#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
    int typecode_size = mp_binary_get_size('@', typecode, NULL);
    if (typecode_size <= 0) {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
    }
    mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
    #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
    o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
    #elif MICROPY_PY_BUILTINS_BYTEARRAY
    o->base.type = &mp_type_bytearray;
    #else
    o->base.type = &mp_type_array;
    #endif
    o->typecode = typecode;
    o->free = 0;
    o->len = n;
119
    o->items = m_new(byte, typecode_size * o->len);
120
121
122
    return o;
}
#endif
123

124
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
125
STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    // bytearrays can be raw-initialised from anything with the buffer protocol
    // other arrays can only be raw-initialised from bytes and bytearray objects
    mp_buffer_info_t bufinfo;
    if (((MICROPY_PY_BUILTINS_BYTEARRAY
            && typecode == BYTEARRAY_TYPECODE)
        || (MICROPY_PY_ARRAY
            && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes)
                || MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))
        && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
        // construct array from raw bytes
        // we round-down the len to make it a multiple of sz (CPython raises error)
        int sz = mp_binary_get_size('@', typecode, NULL);
        mp_uint_t len = bufinfo.len / sz;
        mp_obj_array_t *o = array_new(typecode, len);
        memcpy(o->items, bufinfo.buf, len * sz);
        return o;
    }

    mp_uint_t len;
145
146
147
148
149
150
151
152
153
154
    // Try to create array of exact len if initializer len is known
    mp_obj_t len_in = mp_obj_len_maybe(initializer);
    if (len_in == MP_OBJ_NULL) {
        len = 0;
    } else {
        len = MP_OBJ_SMALL_INT_VALUE(len_in);
    }

    mp_obj_array_t *array = array_new(typecode, len);

Damien George's avatar
Damien George committed
155
    mp_obj_t iterable = mp_getiter(initializer);
156
    mp_obj_t item;
157
    mp_uint_t i = 0;
158
    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
159
160
161
        if (len == 0) {
            array_append(array, item);
        } else {
162
            mp_binary_set_val_array(typecode, array->items, i++, item);
163
164
165
166
167
        }
    }

    return array;
}
168
#endif
169

170
#if MICROPY_PY_ARRAY
171
STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
172
    (void)type_in;
173
    mp_arg_check_num(n_args, n_kw, 1, 2, false);
174
175

    // get typecode
176
    mp_uint_t l;
177
    const char *typecode = mp_obj_str_get_data(args[0], &l);
178

179
    if (n_args == 1) {
180
        // 1 arg: make an empty array
181
        return array_new(*typecode, 0);
182
    } else {
183
        // 2 args: construct the array from the given object
184
        return array_construct(*typecode, args[1]);
185
    }
186
}
187
#endif
188

189
#if MICROPY_PY_BUILTINS_BYTEARRAY
190
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
191
    (void)type_in;
192
    mp_arg_check_num(n_args, n_kw, 0, 1, false);
193

194
195
196
    if (n_args == 0) {
        // no args: construct an empty bytearray
        return array_new(BYTEARRAY_TYPECODE, 0);
197
    } else if (MP_OBJ_IS_INT(args[0])) {
198
        // 1 arg, an integer: construct a blank bytearray of that length
199
        mp_uint_t len = mp_obj_get_int(args[0]);
200
201
202
        mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
        memset(o->items, 0, len);
        return o;
203
    } else {
204
        // 1 arg: construct the bytearray from that
205
        return array_construct(BYTEARRAY_TYPECODE, args[0]);
206
    }
207
}
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#endif

#if MICROPY_PY_BUILTINS_MEMORYVIEW
STATIC mp_obj_t memoryview_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
    // TODO possibly allow memoryview constructor to take start/stop so that one
    // can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)

    mp_arg_check_num(n_args, n_kw, 1, 1, false);

    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);

    mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
    self->base.type = type_in;
    self->typecode = bufinfo.typecode;
    self->free = 0;
    self->len = bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL); // element len
    self->items = bufinfo.buf;

    // test if the object can be written to
    if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
229
        self->typecode |= 0x80; // used to indicate writable buffer
230
231
232
233
234
    }

    return self;
}
#endif
235

236
STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
237
238
    mp_obj_array_t *o = o_in;
    switch (op) {
Damien George's avatar
Damien George committed
239
240
        case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
241
        default: return MP_OBJ_NULL; // op not supported
242
243
244
    }
}

245
STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
246
    mp_obj_array_t *lhs = lhs_in;
247
    switch (op) {
248
        case MP_BINARY_OP_ADD: {
249
250
251
252
253
254
255
256
257
258
259
260
261
262
            // allow to add anything that has the buffer protocol (extension to CPython)
            mp_buffer_info_t lhs_bufinfo;
            mp_buffer_info_t rhs_bufinfo;
            array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
            mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);

            int sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);

            // convert byte count to element count (in case rhs is not multiple of sz)
            mp_uint_t rhs_len = rhs_bufinfo.len / sz;

            // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
            mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
            mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
263
264
265
266
267
268
269
270
271
272
273
274
275
            return res;
        }

        case MP_BINARY_OP_INPLACE_ADD: {
            #if MICROPY_PY_BUILTINS_MEMORYVIEW
            if (lhs->base.type == &mp_type_memoryview) {
                return MP_OBJ_NULL; // op not supported
            }
            #endif
            array_extend(lhs, rhs_in);
            return lhs;
        }

276
277
278
279
280
        case MP_BINARY_OP_EQUAL: {
            mp_buffer_info_t lhs_bufinfo;
            mp_buffer_info_t rhs_bufinfo;
            array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
            if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
281
                return mp_const_false;
282
283
284
            }
            return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
        }
285

286
287
288
289
290
        default:
            return MP_OBJ_NULL; // op not supported
    }
}

291
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
292
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
293
    // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
294
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
295
    mp_obj_array_t *self = self_in;
296

297
    if (self->free == 0) {
298
        int item_sz = mp_binary_get_size('@', self->typecode, NULL);
299
300
        // TODO: alloc policy
        self->free = 8;
301
        self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free));
302
        mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);
303
    }
304
    mp_binary_set_val_array(self->typecode, self->items, self->len++, arg);
305
306
307
    self->free--;
    return mp_const_none; // return None, as per CPython
}
308
STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append);
309

310
311
312
313
314
STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
    // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
    mp_obj_array_t *self = self_in;

315
316
317
    // allow to extend by anything that has the buffer protocol (extension to CPython)
    mp_buffer_info_t arg_bufinfo;
    mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);
318
319
320

    int sz = mp_binary_get_size('@', self->typecode, NULL);

321
322
323
    // convert byte count to element count
    mp_uint_t len = arg_bufinfo.len / sz;

324
    // make sure we have enough room to extend
325
326
    // TODO: alloc policy; at the moment we go conservative
    if (self->free < len) {
327
        self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz);
328
329
330
        self->free = 0;
    } else {
        self->free -= len;
331
332
333
    }

    // extend
334
335
    mp_seq_copy((byte*)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
    self->len += len;
336
337
338
339
340
341

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend);
#endif

342
STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
343
    if (value == MP_OBJ_NULL) {
344
345
        // delete item
        // TODO implement
346
347
        // TODO: confirmed that both bytearray and array.array support
        // slice deletion
348
        return MP_OBJ_NULL; // op not supported
349
350
    } else {
        mp_obj_array_t *o = self_in;
351
352
353
        if (0) {
#if MICROPY_PY_BUILTINS_SLICE
        } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
354
355
            mp_bound_slice_t slice;
            if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
356
                nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
357
                    "only slices with step=1 (aka None) are supported"));
358
            }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
            if (value != MP_OBJ_SENTINEL) {
                #if MICROPY_PY_ARRAY_SLICE_ASSIGN
                // Assign
                if (!MP_OBJ_IS_TYPE(value, &mp_type_array) && !MP_OBJ_IS_TYPE(value, &mp_type_bytearray)) {
                    mp_not_implemented("array required on right side");
                }
                mp_obj_array_t *src_slice = value;
                int item_sz = mp_binary_get_size('@', o->typecode, NULL);
                if (item_sz != mp_binary_get_size('@', src_slice->typecode, NULL)) {
                    mp_not_implemented("arrays should be compatible");
                }

                // TODO: check src/dst compat
                mp_int_t len_adj = src_slice->len - (slice.stop - slice.start);
                if (len_adj > 0) {
                    if (len_adj > o->free) {
                        // TODO: alloc policy; at the moment we go conservative
                        o->items = m_realloc(o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
                        o->free = 0;
                    }
                    mp_seq_replace_slice_grow_inplace(o->items, o->len,
                        slice.start, slice.stop, src_slice->items, src_slice->len, len_adj, item_sz);
                } else {
                    mp_seq_replace_slice_no_grow(o->items, o->len,
                        slice.start, slice.stop, src_slice->items, src_slice->len, item_sz);
                    // Clear "freed" elements at the end of list
                    // TODO: This is actually only needed for typecode=='O'
                    mp_seq_clear(o->items, o->len + len_adj, o->len, item_sz);
                    // TODO: alloc policy after shrinking
                }
                o->len += len_adj;
                return mp_const_none;
                #else
                return MP_OBJ_NULL; // op not supported
                #endif
            }

396
            mp_obj_array_t *res;
397
            int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
398
            assert(sz > 0);
399
400
401
402
403
404
            if (0) {
                // dummy
            #if MICROPY_PY_BUILTINS_MEMORYVIEW
            } else if (o->base.type == &mp_type_memoryview) {
                res = m_new_obj(mp_obj_array_t);
                *res = *o;
405
                res->free += slice.start;
406
407
408
409
                res->len = slice.stop - slice.start;
            #endif
            } else {
                res = array_new(o->typecode, slice.stop - slice.start);
410
                memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
411
            }
412
            return res;
413
#endif
414
        } else {
415
            mp_uint_t index = mp_get_index(o->base.type, o->len, index_in, false);
416
417
418
419
420
421
422
423
424
            #if MICROPY_PY_BUILTINS_MEMORYVIEW
            if (o->base.type == &mp_type_memoryview) {
                index += o->free;
                if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) {
                    // store to read-only memoryview
                    return MP_OBJ_NULL;
                }
            }
            #endif
425
426
            if (value == MP_OBJ_SENTINEL) {
                // load
427
                return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
428
429
            } else {
                // store
430
                mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
431
432
                return mp_const_none;
            }
433
        }
434
    }
435
436
}

437
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
438
    mp_obj_array_t *o = o_in;
439
440
441
442
    int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
    bufinfo->buf = o->items;
    bufinfo->len = o->len * sz;
    bufinfo->typecode = o->typecode & TYPECODE_MASK;
443
    #if MICROPY_PY_BUILTINS_MEMORYVIEW
444
445
446
447
448
    if (o->base.type == &mp_type_memoryview) {
        if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) {
            // read-only memoryview
            return 1;
        }
449
        bufinfo->buf = (uint8_t*)bufinfo->buf + (mp_uint_t)o->free * sz;
450
451
    }
    #endif
452
453
454
    return 0;
}

455
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
456
457
STATIC const mp_map_elem_t array_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
458
    { MP_OBJ_NEW_QSTR(MP_QSTR_extend), (mp_obj_t)&array_extend_obj },
459
460
};

461
STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
462
#endif
463

464
#if MICROPY_PY_ARRAY
465
const mp_obj_type_t mp_type_array = {
466
    { &mp_type_type },
467
    .name = MP_QSTR_array,
468
469
    .print = array_print,
    .make_new = array_make_new,
Paul Sokolovsky's avatar
Paul Sokolovsky committed
470
    .getiter = array_iterator_new,
471
    .unary_op = array_unary_op,
472
    .binary_op = array_binary_op,
473
    .subscr = array_subscr,
474
    .buffer_p = { .get_buffer = array_get_buffer },
475
    .locals_dict = (mp_obj_t)&array_locals_dict,
476
};
477
#endif
478

479
#if MICROPY_PY_BUILTINS_BYTEARRAY
480
481
482
483
484
485
486
const mp_obj_type_t mp_type_bytearray = {
    { &mp_type_type },
    .name = MP_QSTR_bytearray,
    .print = array_print,
    .make_new = bytearray_make_new,
    .getiter = array_iterator_new,
    .unary_op = array_unary_op,
487
    .binary_op = array_binary_op,
488
    .subscr = array_subscr,
489
490
491
    .buffer_p = { .get_buffer = array_get_buffer },
    .locals_dict = (mp_obj_t)&array_locals_dict,
};
492
#endif
493

494
495
496
497
498
499
500
501
502
503
504
505
#if MICROPY_PY_BUILTINS_MEMORYVIEW
const mp_obj_type_t mp_type_memoryview = {
    { &mp_type_type },
    .name = MP_QSTR_memoryview,
    .make_new = memoryview_make_new,
    .getiter = array_iterator_new,
    .unary_op = array_unary_op,
    .binary_op = array_binary_op,
    .subscr = array_subscr,
    .buffer_p = { .get_buffer = array_get_buffer },
};
#endif
506

507
/* unused
508
mp_uint_t mp_obj_array_len(mp_obj_t self_in) {
509
510
    return ((mp_obj_array_t *)self_in)->len;
}
511
*/
512

513
#if MICROPY_PY_BUILTINS_BYTEARRAY
514
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
515
516
517
518
    mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
    memcpy(o->items, items, n);
    return o;
}
Paul Sokolovsky's avatar
Paul Sokolovsky committed
519

520
// Create bytearray which references specified memory area
521
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items) {
522
    mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
523
    o->base.type = &mp_type_bytearray;
524
525
526
527
528
529
    o->typecode = BYTEARRAY_TYPECODE;
    o->free = 0;
    o->len = n;
    o->items = items;
    return o;
}
530
#endif
531

Paul Sokolovsky's avatar
Paul Sokolovsky committed
532
/******************************************************************************/
533
// array iterator
Paul Sokolovsky's avatar
Paul Sokolovsky committed
534
535
536
537

typedef struct _mp_obj_array_it_t {
    mp_obj_base_t base;
    mp_obj_array_t *array;
538
    mp_uint_t offset;
539
    mp_uint_t cur;
Paul Sokolovsky's avatar
Paul Sokolovsky committed
540
541
} mp_obj_array_it_t;

542
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
543
544
    mp_obj_array_it_t *self = self_in;
    if (self->cur < self->array->len) {
545
        return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
546
    } else {
547
        return MP_OBJ_STOP_ITERATION;
Paul Sokolovsky's avatar
Paul Sokolovsky committed
548
549
550
    }
}

551
STATIC const mp_obj_type_t array_it_type = {
552
    { &mp_type_type },
553
    .name = MP_QSTR_iterator,
554
    .getiter = mp_identity,
Paul Sokolovsky's avatar
Paul Sokolovsky committed
555
556
557
    .iternext = array_it_iternext,
};

558
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
559
    mp_obj_array_t *array = array_in;
560
    mp_obj_array_it_t *o = m_new0(mp_obj_array_it_t, 1);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
561
562
    o->base.type = &array_it_type;
    o->array = array;
563
564
565
566
567
    #if MICROPY_PY_BUILTINS_MEMORYVIEW
    if (array->base.type == &mp_type_memoryview) {
        o->offset = array->free;
    }
    #endif
Paul Sokolovsky's avatar
Paul Sokolovsky committed
568
569
    return o;
}
570

571
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW