1*eabc0478Schristos /* $NetBSD: minheap-internal.h,v 1.6 2024/08/18 20:47:21 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 58585484eSchristos * 68585484eSchristos * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com> 78585484eSchristos * 88585484eSchristos * Redistribution and use in source and binary forms, with or without 98585484eSchristos * modification, are permitted provided that the following conditions 108585484eSchristos * are met: 118585484eSchristos * 1. Redistributions of source code must retain the above copyright 128585484eSchristos * notice, this list of conditions and the following disclaimer. 138585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 148585484eSchristos * notice, this list of conditions and the following disclaimer in the 158585484eSchristos * documentation and/or other materials provided with the distribution. 168585484eSchristos * 3. The name of the author may not be used to endorse or promote products 178585484eSchristos * derived from this software without specific prior written permission. 188585484eSchristos * 198585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 208585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 218585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 228585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 238585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 248585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 258585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 268585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 278585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 288585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 298585484eSchristos */ 308585484eSchristos #ifndef MINHEAP_INTERNAL_H_INCLUDED_ 318585484eSchristos #define MINHEAP_INTERNAL_H_INCLUDED_ 328585484eSchristos 338585484eSchristos #include "event2/event-config.h" 348585484eSchristos #include "evconfig-private.h" 358585484eSchristos #include "event2/event.h" 368585484eSchristos #include "event2/event_struct.h" 378585484eSchristos #include "event2/util.h" 388585484eSchristos #include "util-internal.h" 398585484eSchristos #include "mm-internal.h" 408585484eSchristos 418585484eSchristos typedef struct min_heap 428585484eSchristos { 438585484eSchristos struct event** p; 448585484eSchristos unsigned n, a; 458585484eSchristos } min_heap_t; 468585484eSchristos 478585484eSchristos static inline void min_heap_ctor_(min_heap_t* s); 488585484eSchristos static inline void min_heap_dtor_(min_heap_t* s); 498585484eSchristos static inline void min_heap_elem_init_(struct event* e); 508585484eSchristos static inline int min_heap_elt_is_top_(const struct event *e); 518585484eSchristos static inline int min_heap_empty_(min_heap_t* s); 528585484eSchristos static inline unsigned min_heap_size_(min_heap_t* s); 538585484eSchristos static inline struct event* min_heap_top_(min_heap_t* s); 548585484eSchristos static inline int min_heap_reserve_(min_heap_t* s, unsigned n); 558585484eSchristos static inline int min_heap_push_(min_heap_t* s, struct event* e); 568585484eSchristos static inline struct event* min_heap_pop_(min_heap_t* s); 578585484eSchristos static inline int min_heap_adjust_(min_heap_t *s, struct event* e); 588585484eSchristos static inline int min_heap_erase_(min_heap_t* s, struct event* e); 598585484eSchristos static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e); 608585484eSchristos static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e); 618585484eSchristos static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e); 628585484eSchristos 638585484eSchristos #define min_heap_elem_greater(a, b) \ 648585484eSchristos (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >)) 658585484eSchristos 668585484eSchristos void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; } 678585484eSchristos void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); } 688585484eSchristos void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; } 698585484eSchristos int min_heap_empty_(min_heap_t* s) { return 0u == s->n; } 708585484eSchristos unsigned min_heap_size_(min_heap_t* s) { return s->n; } 718585484eSchristos struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; } 728585484eSchristos 738585484eSchristos int min_heap_push_(min_heap_t* s, struct event* e) 748585484eSchristos { 75*eabc0478Schristos if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1)) 768585484eSchristos return -1; 778585484eSchristos min_heap_shift_up_(s, s->n++, e); 788585484eSchristos return 0; 798585484eSchristos } 808585484eSchristos 818585484eSchristos struct event* min_heap_pop_(min_heap_t* s) 828585484eSchristos { 838585484eSchristos if (s->n) 848585484eSchristos { 858585484eSchristos struct event* e = *s->p; 868585484eSchristos min_heap_shift_down_(s, 0u, s->p[--s->n]); 878585484eSchristos e->ev_timeout_pos.min_heap_idx = -1; 888585484eSchristos return e; 898585484eSchristos } 908585484eSchristos return 0; 918585484eSchristos } 928585484eSchristos 938585484eSchristos int min_heap_elt_is_top_(const struct event *e) 948585484eSchristos { 958585484eSchristos return e->ev_timeout_pos.min_heap_idx == 0; 968585484eSchristos } 978585484eSchristos 988585484eSchristos int min_heap_erase_(min_heap_t* s, struct event* e) 998585484eSchristos { 1008585484eSchristos if (-1 != e->ev_timeout_pos.min_heap_idx) 1018585484eSchristos { 1028585484eSchristos struct event *last = s->p[--s->n]; 1038585484eSchristos unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; 1048585484eSchristos /* we replace e with the last element in the heap. We might need to 1058585484eSchristos shift it upward if it is less than its parent, or downward if it is 1068585484eSchristos greater than one or both its children. Since the children are known 1078585484eSchristos to be less than the parent, it can't need to shift both up and 1088585484eSchristos down. */ 1098585484eSchristos if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last)) 1108585484eSchristos min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last); 1118585484eSchristos else 1128585484eSchristos min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last); 1138585484eSchristos e->ev_timeout_pos.min_heap_idx = -1; 1148585484eSchristos return 0; 1158585484eSchristos } 1168585484eSchristos return -1; 1178585484eSchristos } 1188585484eSchristos 1198585484eSchristos int min_heap_adjust_(min_heap_t *s, struct event *e) 1208585484eSchristos { 1218585484eSchristos if (-1 == e->ev_timeout_pos.min_heap_idx) { 1228585484eSchristos return min_heap_push_(s, e); 1238585484eSchristos } else { 1248585484eSchristos unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; 1258585484eSchristos /* The position of e has changed; we shift it up or down 1268585484eSchristos * as needed. We can't need to do both. */ 1278585484eSchristos if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e)) 1288585484eSchristos min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e); 1298585484eSchristos else 1308585484eSchristos min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e); 1318585484eSchristos return 0; 1328585484eSchristos } 133b8ecfcfeSchristos } 1348585484eSchristos 1358585484eSchristos int min_heap_reserve_(min_heap_t* s, unsigned n) 1368585484eSchristos { 1378585484eSchristos if (s->a < n) 1388585484eSchristos { 1398585484eSchristos struct event** p; 1408585484eSchristos unsigned a = s->a ? s->a * 2 : 8; 1418585484eSchristos if (a < n) 1428585484eSchristos a = n; 143*eabc0478Schristos #if (SIZE_MAX == UINT32_MAX) 144*eabc0478Schristos if (a > SIZE_MAX / sizeof *p) 145*eabc0478Schristos return -1; 146*eabc0478Schristos #endif 1478585484eSchristos if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p))) 1488585484eSchristos return -1; 1498585484eSchristos s->p = p; 1508585484eSchristos s->a = a; 1518585484eSchristos } 1528585484eSchristos return 0; 1538585484eSchristos } 1548585484eSchristos 1558585484eSchristos void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e) 1568585484eSchristos { 1578585484eSchristos unsigned parent = (hole_index - 1) / 2; 1588585484eSchristos do 1598585484eSchristos { 1608585484eSchristos (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; 1618585484eSchristos hole_index = parent; 1628585484eSchristos parent = (hole_index - 1) / 2; 1638585484eSchristos } while (hole_index && min_heap_elem_greater(s->p[parent], e)); 1648585484eSchristos (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 1658585484eSchristos } 1668585484eSchristos 1678585484eSchristos void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) 1688585484eSchristos { 1698585484eSchristos unsigned parent = (hole_index - 1) / 2; 1708585484eSchristos while (hole_index && min_heap_elem_greater(s->p[parent], e)) 1718585484eSchristos { 1728585484eSchristos (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; 1738585484eSchristos hole_index = parent; 1748585484eSchristos parent = (hole_index - 1) / 2; 1758585484eSchristos } 1768585484eSchristos (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 1778585484eSchristos } 1788585484eSchristos 1798585484eSchristos void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) 1808585484eSchristos { 1818585484eSchristos unsigned min_child = 2 * (hole_index + 1); 1828585484eSchristos while (min_child <= s->n) 1838585484eSchristos { 1848585484eSchristos min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]); 1858585484eSchristos if (!(min_heap_elem_greater(e, s->p[min_child]))) 1868585484eSchristos break; 1878585484eSchristos (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index; 1888585484eSchristos hole_index = min_child; 1898585484eSchristos min_child = 2 * (hole_index + 1); 1908585484eSchristos } 1918585484eSchristos (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; 1928585484eSchristos } 1938585484eSchristos 1948585484eSchristos #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */ 195