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.
This commit is contained in:
Paul Sokolovsky 2015-02-27 22:16:05 +02:00
parent 0bb971370b
commit cefcbb22b2
5 changed files with 56 additions and 18 deletions

View File

@ -409,6 +409,12 @@ typedef double mp_float_t;
#define MICROPY_PY_ARRAY (1)
#endif
// Whether to support slice assignments for array (and bytearray).
// This is rarely used, but adds ~0.5K of code.
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
#endif
// Whether to provide "collections" module
#ifndef MICROPY_PY_COLLECTIONS
#define MICROPY_PY_COLLECTIONS (1)

View File

@ -616,15 +616,15 @@ mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value);
mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_t) \
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * sizeof(item_t));*/ \
memcpy(dest + beg, slice, slice_len * sizeof(item_t)); \
/*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
memmove(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * (item_sz));*/ \
memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \
/*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \
memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz));
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_t) \
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t));*/ \
memmove(dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t)); \
memcpy(dest + beg, slice, slice_len * sizeof(item_t));
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \
memmove(((char*)dest) + (beg + len_adj) * (item_sz), ((char*)dest) + (beg) * (item_sz), (dest_len - beg) * (item_sz)); \
memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz));
#endif // __MICROPY_INCLUDED_PY_OBJ_H__

View File

@ -351,17 +351,48 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
if (0) {
#if MICROPY_PY_BUILTINS_SLICE
} else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
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)
return MP_OBJ_NULL; // op not supported
}
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
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
}
mp_obj_array_t *res;
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
assert(sz > 0);

View File

@ -165,7 +165,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_int_t len_adj = slice.start - slice.stop;
//printf("Len adj: %d\n", len_adj);
assert(len_adj <= 0);
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, mp_obj_t);
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, sizeof(*self->items));
// Clear "freed" elements at the end of list
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
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) {
self->alloc = self->len + len_adj;
}
mp_seq_replace_slice_grow_inplace(self->items, self->len,
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, mp_obj_t);
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, sizeof(*self->items));
} else {
mp_seq_replace_slice_no_grow(self->items, self->len,
slice_out.start, slice_out.stop, slice->items, slice->len, mp_obj_t);
slice_out.start, slice_out.stop, slice->items, slice->len, sizeof(*self->items));
// Clear "freed" elements at the end of list
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
// TODO: apply allocation policy re: alloc_size

View File

@ -60,6 +60,7 @@
#define MICROPY_PY_BUILTINS_COMPILE (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_PLATFORM "linux"
#define MICROPY_PY_SYS_MAXSIZE (1)