Skip to content

Commit cefcbb2

Browse files
committed
objarray: Implement array slice assignment.
This is rarely used feature which takes enough code to implement, so is controlled by MICROPY_PY_ARRAY_SLICE_ASSIGN config setting, default off. But otherwise it may be useful, as allows to update arbitrary-sized data buffers in-place. Slice is yet to implement, and actually, slice assignment implemented in such a way that RHS of assignment should be array of the exact same item typecode as LHS. CPython has it more relaxed, where RHS can be any sequence of compatible types (e.g. it's possible to assign list of int's to a bytearray slice). Overall, when all "slice write" features are implemented, it may cost ~1KB of code.
1 parent 0bb9713 commit cefcbb2

5 files changed

Lines changed: 57 additions & 19 deletions

File tree

py/mpconfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,12 @@ typedef double mp_float_t;
409409
#define MICROPY_PY_ARRAY (1)
410410
#endif
411411

412+
// Whether to support slice assignments for array (and bytearray).
413+
// This is rarely used, but adds ~0.5K of code.
414+
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
415+
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
416+
#endif
417+
412418
// Whether to provide "collections" module
413419
#ifndef MICROPY_PY_COLLECTIONS
414420
#define MICROPY_PY_COLLECTIONS (1)

py/obj.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -616,15 +616,15 @@ mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value);
616616
mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
617617
// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
618618
#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
619-
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_t) \
620-
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * sizeof(item_t));*/ \
621-
memcpy(dest + beg, slice, slice_len * sizeof(item_t)); \
622-
/*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
623-
memmove(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
624-
625-
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_t) \
626-
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t));*/ \
627-
memmove(dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t)); \
628-
memcpy(dest + beg, slice, slice_len * sizeof(item_t));
619+
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \
620+
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * (item_sz));*/ \
621+
memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \
622+
/*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \
623+
memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz));
624+
625+
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \
626+
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \
627+
memmove(((char*)dest) + (beg + len_adj) * (item_sz), ((char*)dest) + (beg) * (item_sz), (dest_len - beg) * (item_sz)); \
628+
memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz));
629629

630630
#endif // __MICROPY_INCLUDED_PY_OBJ_H__

py/objarray.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,17 +351,48 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
351351
if (0) {
352352
#if MICROPY_PY_BUILTINS_SLICE
353353
} else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
354-
if (value != MP_OBJ_SENTINEL) {
355-
// Only getting a slice is suported so far, not assignment
356-
// TODO: confirmed that both bytearray and array.array support
357-
// slice assignment (incl. of different size)
358-
return MP_OBJ_NULL; // op not supported
359-
}
360354
mp_bound_slice_t slice;
361355
if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
362356
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
363357
"only slices with step=1 (aka None) are supported"));
364358
}
359+
if (value != MP_OBJ_SENTINEL) {
360+
#if MICROPY_PY_ARRAY_SLICE_ASSIGN
361+
// Assign
362+
if (!MP_OBJ_IS_TYPE(value, &mp_type_array) && !MP_OBJ_IS_TYPE(value, &mp_type_bytearray)) {
363+
mp_not_implemented("array required on right side");
364+
}
365+
mp_obj_array_t *src_slice = value;
366+
int item_sz = mp_binary_get_size('@', o->typecode, NULL);
367+
if (item_sz != mp_binary_get_size('@', src_slice->typecode, NULL)) {
368+
mp_not_implemented("arrays should be compatible");
369+
}
370+
371+
// TODO: check src/dst compat
372+
mp_int_t len_adj = src_slice->len - (slice.stop - slice.start);
373+
if (len_adj > 0) {
374+
if (len_adj > o->free) {
375+
// TODO: alloc policy; at the moment we go conservative
376+
o->items = m_realloc(o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
377+
o->free = 0;
378+
}
379+
mp_seq_replace_slice_grow_inplace(o->items, o->len,
380+
slice.start, slice.stop, src_slice->items, src_slice->len, len_adj, item_sz);
381+
} else {
382+
mp_seq_replace_slice_no_grow(o->items, o->len,
383+
slice.start, slice.stop, src_slice->items, src_slice->len, item_sz);
384+
// Clear "freed" elements at the end of list
385+
// TODO: This is actually only needed for typecode=='O'
386+
mp_seq_clear(o->items, o->len + len_adj, o->len, item_sz);
387+
// TODO: alloc policy after shrinking
388+
}
389+
o->len += len_adj;
390+
return mp_const_none;
391+
#else
392+
return MP_OBJ_NULL; // op not supported
393+
#endif
394+
}
395+
365396
mp_obj_array_t *res;
366397
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
367398
assert(sz > 0);

py/objlist.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
165165
mp_int_t len_adj = slice.start - slice.stop;
166166
//printf("Len adj: %d\n", len_adj);
167167
assert(len_adj <= 0);
168-
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, mp_obj_t);
168+
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, sizeof(*self->items));
169169
// Clear "freed" elements at the end of list
170170
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
171171
self->len += len_adj;
@@ -211,10 +211,10 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
211211
self->alloc = self->len + len_adj;
212212
}
213213
mp_seq_replace_slice_grow_inplace(self->items, self->len,
214-
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, mp_obj_t);
214+
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, sizeof(*self->items));
215215
} else {
216216
mp_seq_replace_slice_no_grow(self->items, self->len,
217-
slice_out.start, slice_out.stop, slice->items, slice->len, mp_obj_t);
217+
slice_out.start, slice_out.stop, slice->items, slice->len, sizeof(*self->items));
218218
// Clear "freed" elements at the end of list
219219
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
220220
// TODO: apply allocation policy re: alloc_size

unix/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#define MICROPY_PY_BUILTINS_COMPILE (1)
6161
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
6262
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
63+
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
6364
#define MICROPY_PY_SYS_EXIT (1)
6465
#define MICROPY_PY_SYS_PLATFORM "linux"
6566
#define MICROPY_PY_SYS_MAXSIZE (1)

0 commit comments

Comments
 (0)