Skip to content

Commit afaaf53

Browse files
committed
objslice: Support arbitrary objects start, stop, and step.
Older int-only encoding is not expressive enough to support arbitrary slice assignment operations.
1 parent 7a4ddd2 commit afaaf53

5 files changed

Lines changed: 42 additions & 38 deletions

File tree

py/obj.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
517517
void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
518518

519519
// slice
520-
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
520+
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
521521

522522
// array
523523
uint mp_obj_array_len(mp_obj_t self_in);

py/objslice.c

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,20 @@ const mp_obj_ellipsis_t mp_const_ellipsis_obj = {{&mp_type_ellipsis}};
6262
// CPython supports 3rd arg (step), plus args can be arbitrary Python objects.
6363
typedef struct _mp_obj_slice_t {
6464
mp_obj_base_t base;
65-
machine_int_t start;
66-
machine_int_t stop;
65+
mp_obj_t start;
66+
mp_obj_t stop;
67+
mp_obj_t step;
6768
} mp_obj_slice_t;
6869

6970
void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
7071
mp_obj_slice_t *o = o_in;
71-
print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop);
72+
print(env, "slice(");
73+
mp_obj_print_helper(print, env, o->start, PRINT_REPR);
74+
print(env, ", ");
75+
mp_obj_print_helper(print, env, o->stop, PRINT_REPR);
76+
print(env, ", ");
77+
mp_obj_print_helper(print, env, o->step, PRINT_REPR);
78+
print(env, ")");
7279
}
7380

7481
const mp_obj_type_t mp_type_slice = {
@@ -77,39 +84,21 @@ const mp_obj_type_t mp_type_slice = {
7784
.print = slice_print,
7885
};
7986

80-
// TODO: Make sure to handle "empty" values, which are signified by None in CPython
8187
mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
82-
assert(ostep == NULL);
83-
machine_int_t start = 0, stop = 0;
84-
if (ostart != mp_const_none) {
85-
start = mp_obj_get_int(ostart);
86-
}
87-
if (ostop != mp_const_none) {
88-
stop = mp_obj_get_int(ostop);
89-
if (stop == 0) {
90-
// [x:0] is a special case - in our slice object, stop = 0 means
91-
// "end of sequence". Fortunately, [x:0] is an empty seqence for
92-
// any x (including negative). [x:x] is also always empty sequence.
93-
// but x also can be 0. But note that b""[x:x] is b"" for any x (i.e.
94-
// no IndexError, at least in Python 3.3.3). So, we just use -1's to
95-
// signify that. -1 is catchy "special" number in case someone will
96-
// try to print [x:0] slice ever.
97-
start = stop = -1;
98-
}
99-
}
100-
mp_obj_slice_t *o = m_new(mp_obj_slice_t, 1);
88+
mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t);
10189
o->base.type = &mp_type_slice;
102-
o->start = start;
103-
o->stop = stop;
104-
return (mp_obj_t)o;
90+
o->start = ostart;
91+
o->stop = ostop;
92+
o->step = ostep;
93+
return o;
10594
}
10695

107-
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step) {
96+
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) {
10897
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice));
10998
mp_obj_slice_t *self = self_in;
11099
*start = self->start;
111100
*stop = self->stop;
112-
*step = 1;
101+
*step = self->step;
113102
}
114103

115104
#endif

py/objstr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
355355
if (!mp_seq_get_fast_slice_indexes(self_len, index, &start, &stop)) {
356356
assert(0);
357357
}
358+
if (start >= stop) {
359+
return MP_OBJ_NEW_QSTR(MP_QSTR_);
360+
}
358361
return str_new(type, self_data + start, stop - start);
359362
}
360363
#endif

py/sequence.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,24 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void
5252
}
5353

5454
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
55-
machine_int_t start, stop, step;
56-
mp_obj_slice_get(slice, &start, &stop, &step);
57-
if (step != 1) {
55+
mp_obj_t ostart, ostop, ostep;
56+
machine_int_t start, stop;
57+
mp_obj_slice_get(slice, &ostart, &ostop, &ostep);
58+
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
5859
return false;
5960
}
6061

62+
if (ostart == mp_const_none) {
63+
start = 0;
64+
} else {
65+
start = MP_OBJ_SMALL_INT_VALUE(ostart);
66+
}
67+
if (ostop == mp_const_none) {
68+
stop = len;
69+
} else {
70+
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
71+
}
72+
6173
// Unlike subscription, out-of-bounds slice indexes are never error
6274
if (start < 0) {
6375
start = len + start;
@@ -67,7 +79,7 @@ bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_u
6779
} else if (start > len) {
6880
start = len;
6981
}
70-
if (stop <= 0) {
82+
if (stop < 0) {
7183
stop = len + stop;
7284
// CPython returns empty sequence in such case
7385
if (stop < 0) {

py/vm.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -768,12 +768,12 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
768768
if (unum == 2) {
769769
obj2 = POP();
770770
obj1 = TOP();
771-
SET_TOP(mp_obj_new_slice(obj1, obj2, NULL));
771+
SET_TOP(mp_obj_new_slice(obj1, obj2, mp_const_none));
772772
} else {
773-
obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported");
774-
nlr_pop();
775-
fastn[0] = obj1;
776-
return MP_VM_RETURN_EXCEPTION;
773+
mp_obj_t obj3 = POP();
774+
obj2 = POP();
775+
obj1 = TOP();
776+
SET_TOP(mp_obj_new_slice(obj1, obj2, obj3));
777777
}
778778
DISPATCH();
779779
#endif

0 commit comments

Comments
 (0)