1*2b15cb3dSCy Schubert /* 2*2b15cb3dSCy Schubert * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 3*2b15cb3dSCy Schubert * 4*2b15cb3dSCy Schubert * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com> 5*2b15cb3dSCy Schubert * 6*2b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without 7*2b15cb3dSCy Schubert * modification, are permitted provided that the following conditions 8*2b15cb3dSCy Schubert * are met: 9*2b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright 10*2b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer. 11*2b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright 12*2b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the 13*2b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution. 14*2b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products 15*2b15cb3dSCy Schubert * derived from this software without specific prior written permission. 16*2b15cb3dSCy Schubert * 17*2b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18*2b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19*2b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*2b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21*2b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22*2b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23*2b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*2b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25*2b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26*2b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*2b15cb3dSCy Schubert */ 28*2b15cb3dSCy Schubert #ifndef MINHEAP_INTERNAL_H_INCLUDED_ 29*2b15cb3dSCy Schubert #define MINHEAP_INTERNAL_H_INCLUDED_ 30*2b15cb3dSCy Schubert 31*2b15cb3dSCy Schubert #include "event2/event-config.h" 32*2b15cb3dSCy Schubert #include "evconfig-private.h" 33*2b15cb3dSCy Schubert #include "event2/event.h" 34*2b15cb3dSCy Schubert #include "event2/event_struct.h" 35*2b15cb3dSCy Schubert #include "event2/util.h" 36*2b15cb3dSCy Schubert #include "util-internal.h" 37*2b15cb3dSCy Schubert #include "mm-internal.h" 38*2b15cb3dSCy Schubert 39*2b15cb3dSCy Schubert typedef struct min_heap 40*2b15cb3dSCy Schubert { 41*2b15cb3dSCy Schubert struct event** p; 42*2b15cb3dSCy Schubert unsigned n, a; 43*2b15cb3dSCy Schubert } min_heap_t; 44*2b15cb3dSCy Schubert 45*2b15cb3dSCy Schubert static inline void min_heap_ctor_(min_heap_t* s); 46*2b15cb3dSCy Schubert static inline void min_heap_dtor_(min_heap_t* s); 47*2b15cb3dSCy Schubert static inline void min_heap_elem_init_(struct event* e); 48*2b15cb3dSCy Schubert static inline int min_heap_elt_is_top_(const struct event *e); 49*2b15cb3dSCy Schubert static inline int min_heap_empty_(min_heap_t* s); 50*2b15cb3dSCy Schubert static inline unsigned min_heap_size_(min_heap_t* s); 51*2b15cb3dSCy Schubert static inline struct event* min_heap_top_(min_heap_t* s); 52*2b15cb3dSCy Schubert static inline int min_heap_reserve_(min_heap_t* s, unsigned n); 53*2b15cb3dSCy Schubert static inline int min_heap_push_(min_heap_t* s, struct event* e); 54*2b15cb3dSCy Schubert static inline struct event* min_heap_pop_(min_heap_t* s); 55*2b15cb3dSCy Schubert static inline int min_heap_adjust_(min_heap_t *s, struct event* e); 56*2b15cb3dSCy Schubert static inline int min_heap_erase_(min_heap_t* s, struct event* e); 57*2b15cb3dSCy Schubert static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e); 58*2b15cb3dSCy Schubert static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e); 59*2b15cb3dSCy Schubert static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e); 60*2b15cb3dSCy Schubert 61*2b15cb3dSCy Schubert #define min_heap_elem_greater(a, b) \ 62*2b15cb3dSCy Schubert (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >)) 63*2b15cb3dSCy Schubert 64*2b15cb3dSCy Schubert void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; } 65*2b15cb3dSCy Schubert void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); } 66*2b15cb3dSCy Schubert void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; } 67*2b15cb3dSCy Schubert int min_heap_empty_(min_heap_t* s) { return 0u == s->n; } 68*2b15cb3dSCy Schubert unsigned min_heap_size_(min_heap_t* s) { return s->n; } 69*2b15cb3dSCy Schubert struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; } 70*2b15cb3dSCy Schubert 71*2b15cb3dSCy Schubert int min_heap_push_(min_heap_t* s, struct event* e) 72*2b15cb3dSCy Schubert { 73*2b15cb3dSCy Schubert if (min_heap_reserve_(s, s->n + 1)) 74*2b15cb3dSCy Schubert return -1; 75*2b15cb3dSCy Schubert min_heap_shift_up_(s, s->n++, e); 76*2b15cb3dSCy Schubert return 0; 77*2b15cb3dSCy Schubert } 78*2b15cb3dSCy Schubert 79*2b15cb3dSCy Schubert struct event* min_heap_pop_(min_heap_t* s) 80*2b15cb3dSCy Schubert { 81*2b15cb3dSCy Schubert if (s->n) 82*2b15cb3dSCy Schubert { 83*2b15cb3dSCy Schubert struct event* e = *s->p; 84*2b15cb3dSCy Schubert min_heap_shift_down_(s, 0u, s->p[--s->n]); 85*2b15cb3dSCy Schubert e->ev_timeout_pos.min_heap_idx = -1; 86*2b15cb3dSCy Schubert return e; 87*2b15cb3dSCy Schubert } 88*2b15cb3dSCy Schubert return 0; 89*2b15cb3dSCy Schubert } 90*2b15cb3dSCy Schubert 91*2b15cb3dSCy Schubert int min_heap_elt_is_top_(const struct event *e) 92*2b15cb3dSCy Schubert { 93*2b15cb3dSCy Schubert return e->ev_timeout_pos.min_heap_idx == 0; 94*2b15cb3dSCy Schubert } 95*2b15cb3dSCy Schubert 96*2b15cb3dSCy Schubert int min_heap_erase_(min_heap_t* s, struct event* e) 97*2b15cb3dSCy Schubert { 98*2b15cb3dSCy Schubert if (-1 != e->ev_timeout_pos.min_heap_idx) 99*2b15cb3dSCy Schubert { 100*2b15cb3dSCy Schubert struct event *last = s->p[--s->n]; 101*2b15cb3dSCy Schubert unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; 102*2b15cb3dSCy Schubert /* we replace e with the last element in the heap. We might need to 103*2b15cb3dSCy Schubert shift it upward if it is less than its parent, or downward if it is 104*2b15cb3dSCy Schubert greater than one or both its children. Since the children are known 105*2b15cb3dSCy Schubert to be less than the parent, it can't need to shift both up and 106*2b15cb3dSCy Schubert down. */ 107*2b15cb3dSCy Schubert if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last)) 108*2b15cb3dSCy Schubert min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last); 109*2b15cb3dSCy Schubert else 110*2b15cb3dSCy Schubert min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last); 111*2b15cb3dSCy Schubert e->ev_timeout_pos.min_heap_idx = -1; 112*2b15cb3dSCy Schubert return 0; 113*2b15cb3dSCy Schubert } 114*2b15cb3dSCy Schubert return -1; 115*2b15cb3dSCy Schubert } 116*2b15cb3dSCy Schubert 117*2b15cb3dSCy Schubert int min_heap_adjust_(min_heap_t *s, struct event *e) 118*2b15cb3dSCy Schubert { 119*2b15cb3dSCy Schubert if (-1 == e->ev_timeout_pos.min_heap_idx) { 120*2b15cb3dSCy Schubert return min_heap_push_(s, e); 121*2b15cb3dSCy Schubert } else { 122*2b15cb3dSCy Schubert unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; 123*2b15cb3dSCy Schubert /* The position of e has changed; we shift it up or down 124*2b15cb3dSCy Schubert * as needed. We can't need to do both. */ 125*2b15cb3dSCy Schubert if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e)) 126*2b15cb3dSCy Schubert min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e); 127*2b15cb3dSCy Schubert else 128*2b15cb3dSCy Schubert min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e); 129*2b15cb3dSCy Schubert return 0; 130*2b15cb3dSCy Schubert } 131*2b15cb3dSCy Schubert } 132*2b15cb3dSCy Schubert 133*2b15cb3dSCy Schubert int min_heap_reserve_(min_heap_t* s, unsigned n) 134*2b15cb3dSCy Schubert { 135*2b15cb3dSCy Schubert if (s->a < n) 136*2b15cb3dSCy Schubert { 137*2b15cb3dSCy Schubert struct event** p; 138*2b15cb3dSCy Schubert unsigned a = s->a ? s->a * 2 : 8; 139*2b15cb3dSCy Schubert if (a < n) 140*2b15cb3dSCy Schubert a = n; 141*2b15cb3dSCy Schubert if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p))) 142*2b15cb3dSCy Schubert return -1; 143*2b15cb3dSCy Schubert s->p = p; 144*2b15cb3dSCy Schubert s->a = a; 145*2b15cb3dSCy Schubert } 146*2b15cb3dSCy Schubert return 0; 147*2b15cb3dSCy Schubert } 148*2b15cb3dSCy Schubert 149*2b15cb3dSCy Schubert void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e) 150*2b15cb3dSCy Schubert { 151*2b15cb3dSCy Schubert unsigned parent = (hole_index - 1) / 2; 152*2b15cb3dSCy Schubert do 153*2b15cb3dSCy Schubert { 154*2b15cb3dSCy Schubert (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; 155*2b15cb3dSCy Schubert hole_index = parent; 156*2b15cb3dSCy Schubert parent = (hole_index - 1) / 2; 157*2b15cb3dSCy Schubert } while (hole_index && min_heap_elem_greater(s->p[parent], e)); 158*2b15cb3dSCy Schubert (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 159*2b15cb3dSCy Schubert } 160*2b15cb3dSCy Schubert 161*2b15cb3dSCy Schubert void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) 162*2b15cb3dSCy Schubert { 163*2b15cb3dSCy Schubert unsigned parent = (hole_index - 1) / 2; 164*2b15cb3dSCy Schubert while (hole_index && min_heap_elem_greater(s->p[parent], e)) 165*2b15cb3dSCy Schubert { 166*2b15cb3dSCy Schubert (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; 167*2b15cb3dSCy Schubert hole_index = parent; 168*2b15cb3dSCy Schubert parent = (hole_index - 1) / 2; 169*2b15cb3dSCy Schubert } 170*2b15cb3dSCy Schubert (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 171*2b15cb3dSCy Schubert } 172*2b15cb3dSCy Schubert 173*2b15cb3dSCy Schubert void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) 174*2b15cb3dSCy Schubert { 175*2b15cb3dSCy Schubert unsigned min_child = 2 * (hole_index + 1); 176*2b15cb3dSCy Schubert while (min_child <= s->n) 177*2b15cb3dSCy Schubert { 178*2b15cb3dSCy Schubert min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]); 179*2b15cb3dSCy Schubert if (!(min_heap_elem_greater(e, s->p[min_child]))) 180*2b15cb3dSCy Schubert break; 181*2b15cb3dSCy Schubert (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index; 182*2b15cb3dSCy Schubert hole_index = min_child; 183*2b15cb3dSCy Schubert min_child = 2 * (hole_index + 1); 184*2b15cb3dSCy Schubert } 185*2b15cb3dSCy Schubert (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 186*2b15cb3dSCy Schubert } 187*2b15cb3dSCy Schubert 188*2b15cb3dSCy Schubert #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */ 189