11/*
2- * This file is part of the Micro Python project, http://micropython.org/
2+ * This file is part of the MicroPython project, http://micropython.org/
33 *
44 * The MIT License (MIT)
55 *
66 * Copyright (c) 2014 Damien P. George
7+ * Copyright (c) 2016 Paul Sokolovsky
78 *
89 * Permission is hereby granted, free of charge, to any person obtaining a copy
910 * of this software and associated documentation files (the "Software"), to deal
2425 * THE SOFTWARE.
2526 */
2627
28+ #include <string.h>
29+
2730#include "py/nlr.h"
2831#include "py/objlist.h"
2932#include "py/runtime0.h"
3033#include "py/runtime.h"
3134#include "py/smallint.h"
3235
33- #if MICROPY_PY_UHEAPQ
36+ #if MICROPY_PY_UTIMEQ
3437
3538#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD
3639
40+ #define DEBUG 0
41+
3742// the algorithm here is modelled on CPython's heapq.py
3843
39- STATIC mp_obj_list_t * get_heap (mp_obj_t heap_in ) {
40- if (!MP_OBJ_IS_TYPE (heap_in , & mp_type_list )) {
41- nlr_raise (mp_obj_new_exception_msg (& mp_type_TypeError , "heap must be a list" ));
42- }
44+ struct qentry {
45+ mp_uint_t time ;
46+ mp_obj_t callback ;
47+ mp_obj_t args ;
48+ };
49+
50+ typedef struct _mp_obj_utimeq_t {
51+ mp_obj_base_t base ;
52+ mp_uint_t alloc ;
53+ mp_uint_t len ;
54+ struct qentry items [];
55+ } mp_obj_utimeq_t ;
56+
57+
58+ STATIC mp_obj_utimeq_t * get_heap (mp_obj_t heap_in ) {
4359 return MP_OBJ_TO_PTR (heap_in );
4460}
4561
46- STATIC bool time_less_than (mp_obj_t item , mp_obj_t parent ) {
47- if (!MP_OBJ_IS_TYPE (item , & mp_type_tuple ) || !MP_OBJ_IS_TYPE (parent , & mp_type_tuple )) {
48- mp_raise_TypeError ("" );
49- }
50- mp_obj_tuple_t * item_p = MP_OBJ_TO_PTR (item );
51- mp_obj_tuple_t * parent_p = MP_OBJ_TO_PTR (parent );
52- mp_uint_t item_tm = MP_OBJ_SMALL_INT_VALUE (item_p -> items [0 ]);
53- mp_uint_t parent_tm = MP_OBJ_SMALL_INT_VALUE (parent_p -> items [0 ]);
62+ STATIC bool time_less_than (struct qentry * item , struct qentry * parent ) {
63+ mp_uint_t item_tm = item -> time ;
64+ mp_uint_t parent_tm = parent -> time ;
5465 mp_uint_t res = parent_tm - item_tm ;
5566 if ((mp_int_t )res < 0 ) {
5667 res += MODULO ;
5768 }
5869 return res < (MODULO / 2 );
5970}
6071
61- STATIC void heap_siftdown (mp_obj_list_t * heap , mp_uint_t start_pos , mp_uint_t pos , bool timecmp ) {
62- mp_obj_t item = heap -> items [pos ];
72+ STATIC mp_obj_t utimeq_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
73+ mp_arg_check_num (n_args , n_kw , 1 , 1 , false);
74+ mp_uint_t alloc = mp_obj_get_int (args [0 ]);
75+ mp_obj_utimeq_t * o = m_new_obj_var (mp_obj_utimeq_t , struct qentry , alloc );
76+ o -> base .type = type ;
77+ memset (o -> items , 0 , sizeof (* o -> items ) * alloc );
78+ o -> alloc = alloc ;
79+ o -> len = 0 ;
80+ return MP_OBJ_FROM_PTR (o );
81+ }
82+
83+ STATIC void heap_siftdown (mp_obj_utimeq_t * heap , mp_uint_t start_pos , mp_uint_t pos ) {
84+ struct qentry item = heap -> items [pos ];
6385 while (pos > start_pos ) {
6486 mp_uint_t parent_pos = (pos - 1 ) >> 1 ;
65- mp_obj_t parent = heap -> items [parent_pos ];
66- bool lessthan ;
67- if (MP_UNLIKELY (timecmp )) {
68- lessthan = time_less_than (item , parent );
69- } else {
70- lessthan = (mp_binary_op (MP_BINARY_OP_LESS , item , parent ) == mp_const_true );
71- }
87+ struct qentry * parent = & heap -> items [parent_pos ];
88+ bool lessthan = time_less_than (& item , parent );
7289 if (lessthan ) {
73- heap -> items [pos ] = parent ;
90+ heap -> items [pos ] = * parent ;
7491 pos = parent_pos ;
7592 } else {
7693 break ;
@@ -79,19 +96,14 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po
7996 heap -> items [pos ] = item ;
8097}
8198
82- STATIC void heap_siftup (mp_obj_list_t * heap , mp_uint_t pos , bool timecmp ) {
99+ STATIC void heap_siftup (mp_obj_utimeq_t * heap , mp_uint_t pos ) {
83100 mp_uint_t start_pos = pos ;
84101 mp_uint_t end_pos = heap -> len ;
85- mp_obj_t item = heap -> items [pos ];
102+ struct qentry item = heap -> items [pos ];
86103 for (mp_uint_t child_pos = 2 * pos + 1 ; child_pos < end_pos ; child_pos = 2 * pos + 1 ) {
87104 // choose right child if it's <= left child
88105 if (child_pos + 1 < end_pos ) {
89- bool lessthan ;
90- if (MP_UNLIKELY (timecmp )) {
91- lessthan = time_less_than (heap -> items [child_pos ], heap -> items [child_pos + 1 ]);
92- } else {
93- lessthan = (mp_binary_op (MP_BINARY_OP_LESS , heap -> items [child_pos ], heap -> items [child_pos + 1 ]) == mp_const_true );
94- }
106+ bool lessthan = time_less_than (& heap -> items [child_pos ], & heap -> items [child_pos + 1 ]);
95107 if (!lessthan ) {
96108 child_pos += 1 ;
97109 }
@@ -101,51 +113,92 @@ STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos, bool timecmp) {
101113 pos = child_pos ;
102114 }
103115 heap -> items [pos ] = item ;
104- heap_siftdown (heap , start_pos , pos , timecmp );
116+ heap_siftdown (heap , start_pos , pos );
105117}
106118
107119STATIC mp_obj_t mod_utimeq_heappush (size_t n_args , const mp_obj_t * args ) {
108120 mp_obj_t heap_in = args [0 ];
109- mp_obj_list_t * heap = get_heap (heap_in );
110- mp_obj_list_append (heap_in , args [1 ]);
111- bool is_timeq = (n_args > 2 && args [2 ] == mp_const_true );
112- heap_siftdown (heap , 0 , heap -> len - 1 , is_timeq );
121+ mp_obj_utimeq_t * heap = get_heap (heap_in );
122+ if (heap -> len == heap -> alloc ) {
123+ mp_raise_msg (& mp_type_IndexError , "queue overflow" );
124+ }
125+ mp_uint_t l = heap -> len ;
126+ heap -> items [l ].time = MP_OBJ_SMALL_INT_VALUE (args [1 ]);
127+ heap -> items [l ].callback = args [2 ];
128+ heap -> items [l ].args = args [3 ];
129+ heap_siftdown (heap , 0 , heap -> len );
130+ heap -> len ++ ;
113131 return mp_const_none ;
114132}
115- STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_utimeq_heappush_obj , 2 , 3 , mod_utimeq_heappush );
133+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_utimeq_heappush_obj , 4 , 4 , mod_utimeq_heappush );
116134
117- STATIC mp_obj_t mod_utimeq_heappop (size_t n_args , const mp_obj_t * args ) {
118- mp_obj_t heap_in = args [0 ];
119- mp_obj_list_t * heap = get_heap (heap_in );
135+ STATIC mp_obj_t mod_utimeq_heappop (mp_obj_t heap_in , mp_obj_t list_ref ) {
136+ mp_obj_utimeq_t * heap = get_heap (heap_in );
120137 if (heap -> len == 0 ) {
121138 nlr_raise (mp_obj_new_exception_msg (& mp_type_IndexError , "empty heap" ));
122139 }
123- mp_obj_t item = heap -> items [0 ];
140+ mp_obj_list_t * ret = MP_OBJ_TO_PTR (list_ref );
141+ if (!MP_OBJ_IS_TYPE (list_ref , & mp_type_list ) || ret -> len < 3 ) {
142+ mp_raise_TypeError ("" );
143+ }
144+
145+ struct qentry * item = & heap -> items [0 ];
146+ ret -> items [0 ] = MP_OBJ_NEW_SMALL_INT (item -> time );
147+ ret -> items [1 ] = item -> callback ;
148+ ret -> items [2 ] = item -> args ;
124149 heap -> len -= 1 ;
125150 heap -> items [0 ] = heap -> items [heap -> len ];
126- heap -> items [heap -> len ] = MP_OBJ_NULL ; // so we don't retain a pointer
151+ heap -> items [heap -> len ].callback = MP_OBJ_NULL ; // so we don't retain a pointer
152+ heap -> items [heap -> len ].args = MP_OBJ_NULL ;
127153 if (heap -> len ) {
128- bool is_timeq = (n_args > 1 && args [1 ] == mp_const_true );
129- heap_siftup (heap , 0 , is_timeq );
154+ heap_siftup (heap , 0 );
130155 }
131- return item ;
156+ return mp_const_none ;
132157}
133- STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_utimeq_heappop_obj , 1 , 2 , mod_utimeq_heappop );
158+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (mod_utimeq_heappop_obj , mod_utimeq_heappop );
134159
135- STATIC mp_obj_t mod_utimeq_heapify (mp_obj_t heap_in ) {
136- mp_obj_list_t * heap = get_heap (heap_in );
137- for (mp_uint_t i = heap -> len / 2 ; i > 0 ;) {
138- heap_siftup (heap , -- i , false);
160+ #if DEBUG
161+ STATIC mp_obj_t mod_utimeq_dump (mp_obj_t heap_in ) {
162+ mp_obj_utimeq_t * heap = get_heap (heap_in );
163+ for (int i = 0 ; i < heap -> len ; i ++ ) {
164+ printf (UINT_FMT "\t%p\t%p(%p)\n" , heap -> items [i ].time ,
165+ MP_OBJ_TO_PTR (heap -> items [i ].callback ), MP_OBJ_TO_PTR (heap -> items [i ].args ));
139166 }
140167 return mp_const_none ;
141168}
142- STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_utimeq_heapify_obj , mod_utimeq_heapify );
169+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_utimeq_dump_obj , mod_utimeq_dump );
170+ #endif
171+
172+ STATIC mp_obj_t utimeq_unary_op (mp_uint_t op , mp_obj_t self_in ) {
173+ mp_obj_utimeq_t * self = MP_OBJ_TO_PTR (self_in );
174+ switch (op ) {
175+ case MP_UNARY_OP_BOOL : return mp_obj_new_bool (self -> len != 0 );
176+ case MP_UNARY_OP_LEN : return MP_OBJ_NEW_SMALL_INT (self -> len );
177+ default : return MP_OBJ_NULL ; // op not supported
178+ }
179+ }
180+
181+ STATIC const mp_rom_map_elem_t utimeq_locals_dict_table [] = {
182+ { MP_ROM_QSTR (MP_QSTR_push ), MP_ROM_PTR (& mod_utimeq_heappush_obj ) },
183+ { MP_ROM_QSTR (MP_QSTR_pop ), MP_ROM_PTR (& mod_utimeq_heappop_obj ) },
184+ #if DEBUG
185+ { MP_ROM_QSTR (MP_QSTR_dump ), MP_ROM_PTR (& mod_utimeq_dump_obj ) },
186+ #endif
187+ };
188+
189+ STATIC MP_DEFINE_CONST_DICT (utimeq_locals_dict , utimeq_locals_dict_table );
190+
191+ STATIC const mp_obj_type_t utimeq_type = {
192+ { & mp_type_type },
193+ .name = MP_QSTR_utimeq ,
194+ .make_new = utimeq_make_new ,
195+ .unary_op = utimeq_unary_op ,
196+ .locals_dict = (void * )& utimeq_locals_dict ,
197+ };
143198
144199STATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table [] = {
145200 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_utimeq ) },
146- { MP_ROM_QSTR (MP_QSTR_heappush ), MP_ROM_PTR (& mod_utimeq_heappush_obj ) },
147- { MP_ROM_QSTR (MP_QSTR_heappop ), MP_ROM_PTR (& mod_utimeq_heappop_obj ) },
148- { MP_ROM_QSTR (MP_QSTR_heapify ), MP_ROM_PTR (& mod_utimeq_heapify_obj ) },
201+ { MP_ROM_QSTR (MP_QSTR_utimeq ), MP_ROM_PTR (& utimeq_type ) },
149202};
150203
151204STATIC MP_DEFINE_CONST_DICT (mp_module_utimeq_globals , mp_module_utimeq_globals_table );
@@ -155,4 +208,4 @@ const mp_obj_module_t mp_module_utimeq = {
155208 .globals = (mp_obj_dict_t * )& mp_module_utimeq_globals ,
156209};
157210
158- #endif //MICROPY_PY_UHEAPQ
211+ #endif //MICROPY_PY_UTIMEQ
0 commit comments