xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/minheap-internal.h (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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