objarray.c 18.4 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
#include "mpconfig.h"
33
34
#include "nlr.h"
#include "misc.h"
35
#include "qstr.h"
36
37
38
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
39
#include "binary.h"
40

41
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 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

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

74
75
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);
76
STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
77
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
78
79

/******************************************************************************/
80
// array
81

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

127
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
128
STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
129
130
131
132
133
134
135
136
137
138
139
    uint len;
    // 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
140
    mp_obj_t iterable = mp_getiter(initializer);
141
    mp_obj_t item;
142
    mp_uint_t i = 0;
143
    while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
144
145
146
        if (len == 0) {
            array_append(array, item);
        } else {
147
            mp_binary_set_val_array(typecode, array->items, i++, item);
148
149
150
151
152
        }
    }

    return array;
}
153
#endif
154

155
#if MICROPY_PY_ARRAY
156
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) {
157
    mp_arg_check_num(n_args, n_kw, 1, 2, false);
158
159

    // get typecode
160
    mp_uint_t l;
161
    const char *typecode = mp_obj_str_get_data(args[0], &l);
162

163
    if (n_args == 1) {
164
        // 1 arg: make an empty array
165
        return array_new(*typecode, 0);
166
167
168
    } else {
        // 2 args: construct the array from the given iterator
        return array_construct(*typecode, args[1]);
169
    }
170
}
171
#endif
172

173
#if MICROPY_PY_BUILTINS_BYTEARRAY
174
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) {
175
    mp_arg_check_num(n_args, n_kw, 0, 1, false);
176

177
178
179
180
181
    if (n_args == 0) {
        // no args: construct an empty bytearray
        return array_new(BYTEARRAY_TYPECODE, 0);
    } else if (MP_OBJ_IS_SMALL_INT(args[0])) {
        // 1 arg, an integer: construct a blank bytearray of that length
182
        uint len = MP_OBJ_SMALL_INT_VALUE(args[0]);
183
184
185
        mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
        memset(o->items, 0, len);
        return o;
186
187
188
    } else {
        // 1 arg, an iterator: construct the bytearray from that
        return array_construct(BYTEARRAY_TYPECODE, args[0]);
189
    }
190
}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#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)) {
212
        self->typecode |= 0x80; // used to indicate writable buffer
213
214
215
216
217
    }

    return self;
}
#endif
218

219
STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
220
221
    mp_obj_array_t *o = o_in;
    switch (op) {
Damien George's avatar
Damien George committed
222
223
        case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
224
        default: return MP_OBJ_NULL; // op not supported
225
226
227
    }
}

228
STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
229
    mp_obj_array_t *lhs = lhs_in;
230
    switch (op) {
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
        case MP_BINARY_OP_ADD: {
            #if MICROPY_PY_BUILTINS_MEMORYVIEW
            if (lhs->base.type == &mp_type_memoryview) {
                return MP_OBJ_NULL; // op not supported
            }
            #endif
            // if we get here then lhs is not a memoryview, so we don't need to use (& TYPECODE_MASK)
            if (mp_obj_get_type(rhs_in) != lhs->base.type) {
                return MP_OBJ_NULL; // op not supported
            }
            mp_obj_array_t *rhs = rhs_in;
            if (lhs->typecode != rhs->typecode) {
                return MP_OBJ_NULL; // op not supported
            }
            int sz = mp_binary_get_size('@', lhs->typecode, NULL);
            mp_obj_array_t *res = array_new(lhs->typecode, lhs->len + rhs->len);
            mp_seq_cat((byte*)res->items, lhs->items, lhs->len * sz, rhs->items, rhs->len * sz, byte);
            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;
        }

261
262
263
264
265
        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)) {
266
                return mp_const_false;
267
268
269
            }
            return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
        }
270

271
272
273
274
275
        default:
            return MP_OBJ_NULL; // op not supported
    }
}

276
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
277
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
278
    // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
279
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
280
    mp_obj_array_t *self = self_in;
281

282
    if (self->free == 0) {
283
        int item_sz = mp_binary_get_size('@', self->typecode, NULL);
284
285
286
        // TODO: alloc policy
        self->free = 8;
        self->items = m_realloc(self->items,  item_sz * self->len, item_sz * (self->len + self->free));
287
        mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);
288
    }
289
    mp_binary_set_val_array(self->typecode, self->items, self->len++, arg);
290
291
292
    self->free--;
    return mp_const_none; // return None, as per CPython
}
293
STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append);
294

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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;

    // check for compatible types (array & array, or bytearray & bytearray)
    if (mp_obj_get_type(arg_in) != self->base.type) {
    type_error:
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
            "incompatible type for array operation"));
    }

    // check for compatible typecode
    mp_obj_array_t *arg = arg_in;
    if (self->typecode != arg->typecode) {
        goto type_error;
    }

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

    // make sure we have enough room to extend
    if (self->free < arg->len) {
        // TODO: alloc policy; at the moment we go conservative
        self->items = m_realloc(self->items, (self->len + self->free) * sz, (self->len + arg->len) * sz);
        self->free += arg->len;
    }

    // extend
    mp_seq_copy((byte*)self->items + self->len * sz, arg->items, arg->len * sz, byte);
    self->len += arg->len;
    self->free -= arg->len;

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

332
STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
333
    if (value == MP_OBJ_NULL) {
334
335
        // delete item
        // TODO implement
336
337
        // TODO: confirmed that both bytearray and array.array support
        // slice deletion
338
        return MP_OBJ_NULL; // op not supported
339
340
    } else {
        mp_obj_array_t *o = self_in;
341
342
343
        if (0) {
#if MICROPY_PY_BUILTINS_SLICE
        } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
344
345
346
347
            if (value != MP_OBJ_SENTINEL) {
                // Only getting a slice is suported so far, not assignment
                // TODO: confirmed that both bytearray and array.array support
                // slice assignment (incl. of different size)
348
                return MP_OBJ_NULL; // op not supported
349
            }
350
351
            mp_bound_slice_t slice;
            if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
352
                nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
353
                    "only slices with step=1 (aka None) are supported"));
354
            }
355
            mp_obj_array_t *res;
356
            int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
357
            assert(sz > 0);
358
359
360
361
362
363
            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;
364
                res->free += slice.start;
365
366
367
368
                res->len = slice.stop - slice.start;
            #endif
            } else {
                res = array_new(o->typecode, slice.stop - slice.start);
369
                memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
370
            }
371
            return res;
372
#endif
373
        } else {
374
            mp_uint_t index = mp_get_index(o->base.type, o->len, index_in, false);
375
376
377
378
379
380
381
382
383
            #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
384
385
            if (value == MP_OBJ_SENTINEL) {
                // load
386
                return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
387
388
            } else {
                // store
389
                mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
390
391
                return mp_const_none;
            }
392
        }
393
    }
394
395
}

396
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
397
    mp_obj_array_t *o = o_in;
398
399
400
401
    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;
402
    #if MICROPY_PY_BUILTINS_MEMORYVIEW
403
404
405
406
407
    if (o->base.type == &mp_type_memoryview) {
        if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) {
            // read-only memoryview
            return 1;
        }
408
        bufinfo->buf = (uint8_t*)bufinfo->buf + (mp_uint_t)o->free * sz;
409
410
    }
    #endif
411
412
413
    return 0;
}

414
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
415
416
STATIC const mp_map_elem_t array_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
417
    { MP_OBJ_NEW_QSTR(MP_QSTR_extend), (mp_obj_t)&array_extend_obj },
418
419
};

420
STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
421
#endif
422

423
#if MICROPY_PY_ARRAY
424
const mp_obj_type_t mp_type_array = {
425
    { &mp_type_type },
426
    .name = MP_QSTR_array,
427
428
    .print = array_print,
    .make_new = array_make_new,
Paul Sokolovsky's avatar
Paul Sokolovsky committed
429
    .getiter = array_iterator_new,
430
    .unary_op = array_unary_op,
431
    .binary_op = array_binary_op,
432
    .subscr = array_subscr,
433
    .buffer_p = { .get_buffer = array_get_buffer },
434
    .locals_dict = (mp_obj_t)&array_locals_dict,
435
};
436
#endif
437

438
#if MICROPY_PY_BUILTINS_BYTEARRAY
439
440
441
442
443
444
445
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,
446
    .binary_op = array_binary_op,
447
    .subscr = array_subscr,
448
449
450
    .buffer_p = { .get_buffer = array_get_buffer },
    .locals_dict = (mp_obj_t)&array_locals_dict,
};
451
#endif
452

453
454
455
456
457
458
459
460
461
462
463
464
#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
465

466
/* unused
467
mp_uint_t mp_obj_array_len(mp_obj_t self_in) {
468
469
    return ((mp_obj_array_t *)self_in)->len;
}
470
*/
471

472
#if MICROPY_PY_BUILTINS_BYTEARRAY
473
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
474
475
476
477
    mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
    memcpy(o->items, items, n);
    return o;
}
Paul Sokolovsky's avatar
Paul Sokolovsky committed
478

479
// Create bytearray which references specified memory area
480
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items) {
481
    mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
482
    o->base.type = &mp_type_bytearray;
483
484
485
486
487
488
    o->typecode = BYTEARRAY_TYPECODE;
    o->free = 0;
    o->len = n;
    o->items = items;
    return o;
}
489
#endif
490

Paul Sokolovsky's avatar
Paul Sokolovsky committed
491
/******************************************************************************/
492
// array iterator
Paul Sokolovsky's avatar
Paul Sokolovsky committed
493
494
495
496

typedef struct _mp_obj_array_it_t {
    mp_obj_base_t base;
    mp_obj_array_t *array;
497
    mp_uint_t offset;
498
    mp_uint_t cur;
Paul Sokolovsky's avatar
Paul Sokolovsky committed
499
500
} mp_obj_array_it_t;

501
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
502
503
    mp_obj_array_it_t *self = self_in;
    if (self->cur < self->array->len) {
504
        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
505
    } else {
506
        return MP_OBJ_STOP_ITERATION;
Paul Sokolovsky's avatar
Paul Sokolovsky committed
507
508
509
    }
}

510
STATIC const mp_obj_type_t array_it_type = {
511
    { &mp_type_type },
512
    .name = MP_QSTR_iterator,
513
    .getiter = mp_identity,
Paul Sokolovsky's avatar
Paul Sokolovsky committed
514
515
516
    .iternext = array_it_iternext,
};

517
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
518
    mp_obj_array_t *array = array_in;
519
    mp_obj_array_it_t *o = m_new0(mp_obj_array_it_t, 1);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
520
521
    o->base.type = &array_it_type;
    o->array = array;
522
523
524
525
526
    #if MICROPY_PY_BUILTINS_MEMORYVIEW
    if (array->base.type == &mp_type_memoryview) {
        o->offset = array->free;
    }
    #endif
Paul Sokolovsky's avatar
Paul Sokolovsky committed
527
528
    return o;
}
529

530
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW