8000 py/objdeque: Implement ucollections.deque type with fixed size. · micropython/micropython@970eedc · GitHub
[go: up one dir, main page]

Skip to content

Commit 970eedc

Browse files
Paul Sokolovskydpgeorge
Paul Sokolovsky
authored andcommitted
py/objdeque: Implement ucollections.deque type with fixed size.
So far, implements just append() and popleft() methods, required for a normal queue. Constructor doesn't accept an arbitarry sequence to initialize from (am empty deque is always created), so an empty tuple must be passed as such. Only fixed-size deques are supported, so 2nd argument (size) is required. There's also an extension to CPython - if True is passed as 3rd argument, append(), instead of silently overwriting the oldest item on queue overflow, will throw IndexError. This behavior is desired in many cases, where queues should store information reliably, instead of silently losing some items.
1 parent cced43f commit 970eedc

File tree

5 files changed

+169
-0
lines changed

5 files changed

+169
-0
lines changed

py/modcollections.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030

3131
STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = {
3232
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) },
33+
#if MICROPY_PY_COLLECTIONS_DEQUE
34+
{ MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) },
35+
#endif
3336
{ MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) },
3437
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
3538
{ MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) },

py/mpconfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,11 @@ typedef double mp_float_t;
936936
#define MICROPY_PY_COLLECTIONS (1)
937937
#endif
938938

939+
// Whether to provide "ucollections.deque" type
940+
#ifndef MICROPY_PY_COLLECTIONS_DEQUE
941+
#define MICROPY_PY_COLLECTIONS_DEQUE (0)
942+
#endif
943+
939944
// Whether to provide "collections.OrderedDict" type
940945
#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT
941946
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ extern const mp_obj_type_t mp_type_list;
553553
extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail)
554554
extern const mp_obj_type_t mp_type_enumerate;
555555
extern const mp_obj_type_t mp_type_filter;
556+
extern const mp_obj_type_t mp_type_deque;
556557
extern const mp_obj_type_t mp_type_dict;
557558
extern const mp_obj_type_t mp_type_ordereddict;
558559
extern const mp_obj_type_t mp_type_range;

py/objdeque.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Paul Sokolovsky
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <string.h>
28+
29+
#include "py/mpconfig.h"
30+
#if MICROPY_PY_COLLECTIONS_DEQUE
31+
32+
#include "py/runtime.h"
33+
34+
typedef struct _mp_obj_deque_t {
35+
mp_obj_base_t base;
36+
size_t alloc;
37+
size_t i_get;
38+
size_t i_put;
39+
mp_obj_t *items;
40+
uint32_t flags;
41+
#define FLAG_CHECK_OVERFLOW 1
42+
} mp_obj_deque_t;
43+
44+
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) {
45+
mp_arg_check_num(n_args, n_kw, 2, 3, false);
46+
47+
/* Initialization from existing sequence is not supported, so an empty
48+
tuple must be passed as such. */
49+
if (args[0] != mp_const_empty_tuple) {
50+
mp_raise_ValueError(NULL);
51+
}
52+
53+
mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t);
54+
o->base.type = type;
55+
o->alloc = mp_obj_get_int(args[1]) + 1;
56+
o->i_get = o->i_put = 0;
57+
o->items = m_new(mp_obj_t, o->alloc);
58+
mp_seq_clear(o->items, 0, o->alloc, sizeof(*o->items));
59+
60+
if (n_args > 2) {
61+
o->flags = mp_obj_get_int(args[2]);
62+
}
63+
64+
return MP_OBJ_FROM_PTR(o);
65+
}
66+
67+
STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
68+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
69+
switch (op) {
70+
case MP_UNARY_OP_BOOL:
71+
return mp_obj_new_bool(self->i_get != self->i_put);
72+
case MP_UNARY_OP_LEN: {
73+
mp_int_t len = self->i_put - self->i_get;
74+
if (len < 0) {
75+
len += self->alloc;
76+
}
77+
return MP_OBJ_NEW_SMALL_INT(len);
78+
}
79+
#if MICROPY_PY_SYS_GETSIZEOF
80+
case MP_UNARY_OP_SIZEOF: {
81+
size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;
82+
return MP_OBJ_NEW_SMALL_INT(sz);
83+
}
84+
#endif
85+
default:
86+
return MP_OBJ_NULL; // op not supported
87+
}
88+
}
89+
90+
STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
91+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
92+
93+
size_t new_i_put = self->i_put + 1;
94+
if (new_i_put == self->alloc) {
95+
new_i_put = 0;
96+
}
97+
98+
if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) {
99+
mp_raise_msg(&mp_type_IndexError, "full");
100+
}
101+
102+
self->items[self->i_put] = arg;
103+
self->i_put = new_i_put;
104+
105+
if (self->i_get == new_i_put) {
106+
if (++self->i_get == self->alloc) {
107+
self->i_get = 0;
108+
}
109+
}
110+
111+
return mp_const_none;
112+
}
113+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);
114+
115+
STATIC mp_obj_t deque_popleft(mp_obj_t self_in) {
116+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
117+
118+
if (self->i_get == self->i_put) {
119+
mp_raise_msg(&mp_type_IndexError, "empty");
120+
}
121+
122+
mp_obj_t ret = self->items[self->i_get];
123+
self->items[self->i_get] = MP_OBJ_NULL;
124+
125+
if (++self->i_get == self->alloc) {
126+
self->i_get = 0;
127+
}
128+
129+
return ret;
130+
}
131+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);
132+
133+
STATIC mp_obj_t deque_clear(mp_obj_t self_in) {
134+
mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
135+
self->i_get = self->i_put = 0;
136+
mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));
137+
return mp_const_none;
138+
}
139+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);
140+
141+
STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = {
142+
{ MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) },
143+
#if 0
144+
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) },
145+
#endif
146+
{ MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) },
147+
};
148+
149+
STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);
150+
151+
const mp_obj_type_t mp_type_deque = {
152+
{ &mp_type_type },
153+
.name = MP_QSTR_deque,
154+
.make_new = deque_make_new,
155+
.unary_op = deque_unary_op,
156+
.locals_dict = (mp_obj_dict_t*)&deque_locals_dict,
157+
};
158+
159+
#endif // MICROPY_PY_COLLECTIONS_DEQUE

py/py.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ PY_O_BASENAME = \
158158
objcell.o \
159159
objclosure.o \
160160
objcomplex.o \
161+
objdeque.o \
161162
objdict.o \< 428A /div>
162163
objenumerate.o \
163164
objexcept.o \

0 commit comments

Comments
 (0)
0