2828#include "py/objlist.h"
2929#include "py/runtime0.h"
3030#include "py/runtime.h"
31+ #include "py/smallint.h"
3132
3233#if MICROPY_PY_UHEAPQ
3334
35+ #define MODULO MICROPY_PY_UTIME_TICKS_PERIOD
36+
3437// the algorithm here is modelled on CPython's heapq.py
3538
3639STATIC mp_obj_list_t * get_heap (mp_obj_t heap_in ) {
@@ -40,12 +43,33 @@ STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
4043 return MP_OBJ_TO_PTR (heap_in );
4144}
4245
43- STATIC void heap_siftdown (mp_obj_list_t * heap , mp_uint_t start_pos , mp_uint_t pos ) {
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 ]);
54+ mp_uint_t res = parent_tm - item_tm ;
55+ if ((mp_int_t )res < 0 ) {
56+ res += MODULO ;
57+ }
58+ return res < (MODULO / 2 );
59+ }
60+
61+ STATIC void heap_siftdown (mp_obj_list_t * heap , mp_uint_t start_pos , mp_uint_t pos , bool timecmp ) {
4462 mp_obj_t item = heap -> items [pos ];
4563 while (pos > start_pos ) {
4664 mp_uint_t parent_pos = (pos - 1 ) >> 1 ;
4765 mp_obj_t parent = heap -> items [parent_pos ];
48- if (mp_binary_op (MP_BINARY_OP_LESS , item , parent ) == mp_const_true ) {
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+ }
72+ if (lessthan ) {
4973 heap -> items [pos ] = parent ;
5074 pos = parent_pos ;
5175 } else {
@@ -55,32 +79,43 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po
5579 heap -> items [pos ] = item ;
5680}
5781
58- STATIC void heap_siftup (mp_obj_list_t * heap , mp_uint_t pos ) {
82+ STATIC void heap_siftup (mp_obj_list_t * heap , mp_uint_t pos , bool timecmp ) {
5983 mp_uint_t start_pos = pos ;
6084 mp_uint_t end_pos = heap -> len ;
6185 mp_obj_t item = heap -> items [pos ];
6286 for (mp_uint_t child_pos = 2 * pos + 1 ; child_pos < end_pos ; child_pos = 2 * pos + 1 ) {
6387 // choose right child if it's <= left child
64- if (child_pos + 1 < end_pos && mp_binary_op (MP_BINARY_OP_LESS , heap -> items [child_pos ], heap -> items [child_pos + 1 ]) == mp_const_false ) {
65- child_pos += 1 ;
88+ 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+ }
95+ if (!lessthan ) {
96+ child_pos += 1 ;
97+ }
6698 }
6799 // bubble up the smaller child
68100 heap -> items [pos ] = heap -> items [child_pos ];
69101 pos = child_pos ;
70102 }
71103 heap -> items [pos ] = item ;
72- heap_siftdown (heap , start_pos , pos );
104+ heap_siftdown (heap , start_pos , pos , timecmp );
73105}
74106
75- STATIC mp_obj_t mod_uheapq_heappush (mp_obj_t heap_in , mp_obj_t item ) {
107+ STATIC mp_obj_t mod_uheapq_heappush (size_t n_args , const mp_obj_t * args ) {
108+ mp_obj_t heap_in = args [0 ];
76109 mp_obj_list_t * heap = get_heap (heap_in );
77- mp_obj_list_append (heap_in , item );
78- heap_siftdown (heap , 0 , heap -> len - 1 );
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 );
79113 return mp_const_none ;
80114}
81- STATIC MP_DEFINE_CONST_FUN_OBJ_2 (mod_uheapq_heappush_obj , mod_uheapq_heappush );
115+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_uheapq_heappush_obj , 2 , 3 , mod_uheapq_heappush );
82116
83- STATIC mp_obj_t mod_uheapq_heappop (mp_obj_t heap_in ) {
117+ STATIC mp_obj_t mod_uheapq_heappop (size_t n_args , const mp_obj_t * args ) {
118+ mp_obj_t heap_in = args [0 ];
84119 mp_obj_list_t * heap = get_heap (heap_in );
85120 if (heap -> len == 0 ) {
86121 nlr_raise (mp_obj_new_exception_msg (& mp_type_IndexError , "empty heap" ));
@@ -90,16 +125,17 @@ STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
90125 heap -> items [0 ] = heap -> items [heap -> len ];
91126 heap -> items [heap -> len ] = MP_OBJ_NULL ; // so we don't retain a pointer
92127 if (heap -> len ) {
93- heap_siftup (heap , 0 );
128+ bool is_timeq = (n_args > 1 && args [1 ] == mp_const_true );
129+ heap_siftup (heap , 0 , is_timeq );
94130 }
95131 return item ;
96132}
97- STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_uheapq_heappop_obj , mod_uheapq_heappop );
133+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_uheapq_heappop_obj , 1 , 2 , mod_uheapq_heappop );
98134
99135STATIC mp_obj_t mod_uheapq_heapify (mp_obj_t heap_in ) {
100136 mp_obj_list_t * heap = get_heap (heap_in );
101137 for (mp_uint_t i = heap -> len / 2 ; i > 0 ;) {
102- heap_siftup (heap , -- i );
138+ heap_siftup (heap , -- i , false );
103139 }
104140 return mp_const_none ;
105141}
0 commit comments