Skip to content

Commit 49099ce

Browse files
committed
Expand deque implementation to include iteration and subscripting
1 parent 16a6203 commit 49099ce

File tree

1 file changed

+175
-28
lines changed

1 file changed

+175
-28
lines changed

py/objdeque.c

Lines changed: 175 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,11 @@
2525
*/
2626

2727
#include <unistd.h> // for ssize_t
28-
#include <string.h>
29-
30-
#include "py/mpconfig.h"
31-
#if MICROPY_PY_COLLECTIONS_DEQUE
3228

3329
#include "py/runtime.h"
3430

31+
#if MICROPY_PY_COLLECTIONS_DEQUE
32+
3533
typedef struct _mp_obj_deque_t {
3634
mp_obj_base_t base;
3735
size_t alloc;
@@ -42,14 +40,14 @@ typedef struct _mp_obj_deque_t {
4240
#define FLAG_CHECK_OVERFLOW 1
4341
} mp_obj_deque_t;
4442

45-
STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
46-
mp_arg_check_num(n_args, n_kw, 2, 3, false);
43+
static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg);
44+
static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in);
45+
#if MICROPY_PY_COLLECTIONS_DEQUE_ITER
46+
static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf);
47+
#endif
4748

48-
/* Initialization from existing sequence is not supported, so an empty
49-
tuple must be passed as such. */
50-
if (args[0] != mp_const_empty_tuple) {
51-
mp_raise_ValueError(NULL);
52-
}
49+
static mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
50+
mp_arg_check_num(n_args, n_kw, 2, 3, false);
5351

5452
// Protect against -1 leading to zero-length allocation and bad array access
5553
mp_int_t maxlen = mp_obj_get_int(args[1]);
@@ -66,21 +64,27 @@ STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t
6664
o->flags = mp_obj_get_int(args[2]);
6765
}
6866

67+
mp_obj_deque_extend(MP_OBJ_FROM_PTR(o), args[0]);
68+
6969
return MP_OBJ_FROM_PTR(o);
7070
}
7171

72-
STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
72+
static size_t deque_len(mp_obj_deque_t *self) {
73+
ssize_t len = self->i_put - self->i_get;
74+
if (len < 0) {
75+
len += self->alloc;
76+
}
77+
return len;
78+
}
79+
80+
static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
7381
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
7482
switch (op) {
7583
case MP_UNARY_OP_BOOL:
7684
return mp_obj_new_bool(self->i_get != self->i_put);
77-
case MP_UNARY_OP_LEN: {
78-
ssize_t len = self->i_put - self->i_get;
79-
if (len < 0) {
80-
len += self->alloc;
81-
}
82-
return MP_OBJ_NEW_SMALL_INT(len);
83-
}
85+
case MP_UNARY_OP_LEN:
86+
return MP_OBJ_NEW_SMALL_INT(deque_len(self));
87+
8488
#if MICROPY_PY_SYS_GETSIZEOF
8589
case MP_UNARY_OP_SIZEOF: {
8690
size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;
@@ -92,7 +96,7 @@ STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
9296
}
9397
}
9498

95-
STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
99+
static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
96100
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
97101

98102
size_t new_i_put = self->i_put + 1;
@@ -115,9 +119,48 @@ STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
115119

116120
return mp_const_none;
117121
}
118-
STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);
122+
static MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);
123+
124+
static mp_obj_t mp_obj_deque_appendleft(mp_obj_t self_in, mp_obj_t arg) {
125+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
126+
127+
size_t new_i_get = self->i_get - 1;
128+
if (self->i_get == 0) {
129+
new_i_get = self->alloc - 1;
130+
}
131+
132+
if (self->flags & FLAG_CHECK_OVERFLOW && new_i_get == self->i_put) {
133+
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("full"));
134+
}
135+
136+
self->i_get = new_i_get;
137+
self->items[self->i_get] = arg;
138+
139+
// overwriting first element in deque
140+
if (self->i_put == new_i_get) {
141+
if (self->i_put == 0) {
142+
self->i_put = self->alloc - 1;
143+
} else {
144+
self->i_put--;
145+
}
146+
}
147+
148+
return mp_const_none;
149+
}
150+
static MP_DEFINE_CONST_FUN_OBJ_2(deque_appendleft_obj, mp_obj_deque_appendleft);
119151

120-
STATIC mp_obj_t deque_popleft(mp_obj_t self_in) {
152+
static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in) {
153+
mp_obj_iter_buf_t iter_buf;
154+
mp_obj_t iter = mp_getiter(arg_in, &iter_buf);
155+
mp_obj_t item;
156+
while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
157+
mp_obj_deque_append(self_in, item);
158+
}
159+
return mp_const_none;
160+
}
161+
static MP_DEFINE_CONST_FUN_OBJ_2(deque_extend_obj, mp_obj_deque_extend);
162+
163+
static mp_obj_t deque_popleft(mp_obj_t self_in) {
121164
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
122165

123166
if (self->i_get == self->i_put) {
@@ -133,35 +176,139 @@ STATIC mp_obj_t deque_popleft(mp_obj_t self_in) {
133176

134177
return ret;
135178
}
136-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);
179+
static MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);
180+
181+
static mp_obj_t deque_pop(mp_obj_t self_in) {
182+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
183+
184+
if (self->i_get == self->i_put) {
185+
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty"));
186+
}
187+
188+
if (self->i_put == 0) {
189+
self->i_put = self->alloc - 1;
190+
} else {
191+
self->i_put--;
192+
}
193+
194+
mp_obj_t ret = self->items[self->i_put];
195+
self->items[self->i_put] = MP_OBJ_NULL;
196+
197+
return ret;
198+
}
199+
static MP_DEFINE_CONST_FUN_OBJ_1(deque_pop_obj, deque_pop);
200+
201+
#if MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR
202+
static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
203+
if (value == MP_OBJ_NULL) {
204+
// delete not supported, fall back to mp_obj_subscr() error message
205+
return MP_OBJ_NULL;
206+
}
207+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
208+
209+
size_t offset = mp_get_index(self->base.type, deque_len(self), index, false);
210+
size_t index_val = self->i_get + offset;
211+
if (index_val > self->alloc) {
212+
index_val -= self->alloc;
213+
}
214+
215+
if (value == MP_OBJ_SENTINEL) {
216+
// load
217+
return self->items[index_val];
218+
} else {
219+
// store into deque
220+
self->items[index_val] = value;
221+
return mp_const_none;
222+
}
223+
}
224+
#endif
137225

138226
#if 0
139-
STATIC mp_obj_t deque_clear(mp_obj_t self_in) {
227+
static mp_obj_t deque_clear(mp_obj_t self_in) {
140228
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
141229
self->i_get = self->i_put = 0;
142230
mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));
143231
return mp_const_none;
144232
}
145-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);
233+
static MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);
146234
#endif
147235

148-
STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = {
236+
static const mp_rom_map_elem_t deque_locals_dict_table[] = {
149237
{ MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) },
238+
{ MP_ROM_QSTR(MP_QSTR_appendleft), MP_ROM_PTR(&deque_appendleft_obj) },
239+
{ MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&deque_extend_obj) },
150240
#if 0
151241
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) },
152242
#endif
243+
{ MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&deque_pop_obj) },
153244
{ MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) },
154245
};
155246

156-
STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);
247+
static MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);
248+
249+
#if MICROPY_PY_COLLECTIONS_DEQUE_ITER
250+
#define DEQUE_TYPE_FLAGS MP_TYPE_FLAG_ITER_IS_GETITER
251+
#define DEQUE_TYPE_ITER iter, mp_obj_new_deque_it,
252+
#else
253+
#define DEQUE_TYPE_FLAGS MP_TYPE_FLAG_NONE
254+
#define DEQUE_TYPE_ITER
255+
#endif
256+
257+
#if MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR
258+
#define DEQUE_TYPE_SUBSCR subscr, deque_subscr,
259+
#else
260+
#define DEQUE_TYPE_SUBSCR
261+
#endif
157262

158263
MP_DEFINE_CONST_OBJ_TYPE(
159264
mp_type_deque,
160265
MP_QSTR_deque,
161-
MP_TYPE_FLAG_NONE,
266+
MP_TYPE_FLAG_ITER_IS_GETITER,
162267
make_new, deque_make_new,
163268
unary_op, deque_unary_op,
269+
DEQUE_TYPE_SUBSCR
270+
DEQUE_TYPE_ITER
164271
locals_dict, &deque_locals_dict
165272
);
166273

274+
/******************************************************************************/
275+
/* deque iterator */
276+
277+
#if MICROPY_PY_COLLECTIONS_DEQUE_ITER
278+
279+
typedef struct _mp_obj_deque_it_t {
280+
mp_obj_base_t base;
281+
mp_fun_1_t iternext;
282+
mp_obj_t deque;
283+
size_t cur;
284+
} mp_obj_deque_it_t;
285+
286+
static mp_obj_t deque_it_iternext(mp_obj_t self_in) {
287+
mp_obj_deque_it_t *self = MP_OBJ_TO_PTR(self_in);
288+
mp_obj_deque_t *deque = MP_OBJ_TO_PTR(self->deque);
289+
if (self->cur != deque->i_put) {
290+
mp_obj_t o_out = deque->items[self->cur];
291+
if (++self->cur == deque->alloc) {
292+
self->cur = 0;
293+
}
294+
return o_out;
295+
} else {
296+
return MP_OBJ_STOP_ITERATION;
297+
}
298+
}
299+
300+
static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf) {
301+
mp_obj_deque_t *deque_ = MP_OBJ_TO_PTR(deque);
302+
size_t i_get = deque_->i_get;
303+
assert(sizeof(mp_obj_deque_it_t) <= sizeof(mp_obj_iter_buf_t));
304+
mp_obj_deque_it_t *o = (mp_obj_deque_it_t *)iter_buf;
305+
o->base.type = &mp_type_polymorph_iter;
306+
o->iternext = deque_it_iternext;
307+
o->deque = deque;
308+
o->cur = i_get;
309+
return MP_OBJ_FROM_PTR(o);
310+
}
311+
312+
#endif
313+
167314
#endif // MICROPY_PY_COLLECTIONS_DEQUE

0 commit comments

Comments
 (0)