From 94d8246272b2df7dbfb70ec85ed06e3b13793bac Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Sat, 10 May 2014 22:23:00 +0300
Subject: [PATCH] objlist: Implement non-growing slice assignment.

Slice value to assign can be only a list so far too.
---
 py/obj.h                          |  5 +++++
 py/objlist.c                      | 20 ++++++++++++++++++++
 tests/basics/list_slice_assign.py | 27 +++++++++++++++++++++++++++
 3 files changed, 52 insertions(+)
 create mode 100644 tests/basics/list_slice_assign.py

diff --git a/py/obj.h b/py/obj.h
index 0ec3c29ef..2418b2845 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -573,3 +573,8 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp
 mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
 // 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("memcpy(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
+    memcpy(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
diff --git a/py/objlist.c b/py/objlist.c
index 08c171617..4432b2447 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -173,6 +173,26 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
         uint index_val = mp_get_index(self->base.type, self->len, index, false);
         return self->items[index_val];
     } else {
+#if MICROPY_ENABLE_SLICE
+        if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
+            mp_obj_list_t *self = self_in;
+            assert(MP_OBJ_IS_TYPE(value, &mp_type_list));
+            mp_obj_list_t *slice = value;
+            machine_uint_t start, stop;
+            if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
+                assert(0);
+            }
+            int len_adj = slice->len - (stop - start);
+            //printf("Len adj: %d\n", len_adj);
+            assert(len_adj <= 0);
+            mp_seq_replace_slice_no_grow(self->items, self->len, start, stop, slice->items, slice->len, mp_obj_t);
+            // 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;
+            // TODO: apply allocation policy re: alloc_size
+            return mp_const_none;
+        }
+#endif
         mp_obj_list_store(self_in, index, value);
         return mp_const_none;
     }
diff --git a/tests/basics/list_slice_assign.py b/tests/basics/list_slice_assign.py
new file mode 100644
index 000000000..f88052046
--- /dev/null
+++ b/tests/basics/list_slice_assign.py
@@ -0,0 +1,27 @@
+# test slices; only 2 argument version supported by Micro Python at the moment
+x = list(range(10))
+
+# Assignment
+l = list(x)
+l[1:3] = [10, 20]
+print(l)
+l = list(x)
+l[1:3] = [10]
+print(l)
+l = list(x)
+l[1:3] = []
+print(l)
+
+l = list(x)
+l[:3] = [10, 20]
+print(l)
+l = list(x)
+l[:3] = []
+print(l)
+
+l = list(x)
+l[:-3] = [10, 20]
+print(l)
+l = list(x)
+l[:-3] = []
+print(l)
-- 
GitLab