xref: /freebsd/contrib/ntp/sntp/libevent/minheap-internal.h (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
52b15cb3dSCy Schubert  *
62b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
72b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
82b15cb3dSCy Schubert  * are met:
92b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
102b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
112b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
122b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
132b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
142b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
152b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
162b15cb3dSCy Schubert  *
172b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272b15cb3dSCy Schubert  */
282b15cb3dSCy Schubert #ifndef MINHEAP_INTERNAL_H_INCLUDED_
292b15cb3dSCy Schubert #define MINHEAP_INTERNAL_H_INCLUDED_
302b15cb3dSCy Schubert 
312b15cb3dSCy Schubert #include "event2/event-config.h"
322b15cb3dSCy Schubert #include "evconfig-private.h"
332b15cb3dSCy Schubert #include "event2/event.h"
342b15cb3dSCy Schubert #include "event2/event_struct.h"
352b15cb3dSCy Schubert #include "event2/util.h"
362b15cb3dSCy Schubert #include "util-internal.h"
372b15cb3dSCy Schubert #include "mm-internal.h"
382b15cb3dSCy Schubert 
392b15cb3dSCy Schubert typedef struct min_heap
402b15cb3dSCy Schubert {
412b15cb3dSCy Schubert 	struct event** p;
422b15cb3dSCy Schubert 	unsigned n, a;
432b15cb3dSCy Schubert } min_heap_t;
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert static inline void	     min_heap_ctor_(min_heap_t* s);
462b15cb3dSCy Schubert static inline void	     min_heap_dtor_(min_heap_t* s);
472b15cb3dSCy Schubert static inline void	     min_heap_elem_init_(struct event* e);
482b15cb3dSCy Schubert static inline int	     min_heap_elt_is_top_(const struct event *e);
492b15cb3dSCy Schubert static inline int	     min_heap_empty_(min_heap_t* s);
502b15cb3dSCy Schubert static inline unsigned	     min_heap_size_(min_heap_t* s);
512b15cb3dSCy Schubert static inline struct event*  min_heap_top_(min_heap_t* s);
522b15cb3dSCy Schubert static inline int	     min_heap_reserve_(min_heap_t* s, unsigned n);
532b15cb3dSCy Schubert static inline int	     min_heap_push_(min_heap_t* s, struct event* e);
542b15cb3dSCy Schubert static inline struct event*  min_heap_pop_(min_heap_t* s);
552b15cb3dSCy Schubert static inline int	     min_heap_adjust_(min_heap_t *s, struct event* e);
562b15cb3dSCy Schubert static inline int	     min_heap_erase_(min_heap_t* s, struct event* e);
572b15cb3dSCy Schubert static inline void	     min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
582b15cb3dSCy Schubert static inline void	     min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e);
592b15cb3dSCy Schubert static inline void	     min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
602b15cb3dSCy Schubert 
612b15cb3dSCy Schubert #define min_heap_elem_greater(a, b) \
622b15cb3dSCy Schubert 	(evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
632b15cb3dSCy Schubert 
min_heap_ctor_(min_heap_t * s)642b15cb3dSCy Schubert void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
min_heap_dtor_(min_heap_t * s)652b15cb3dSCy Schubert void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); }
min_heap_elem_init_(struct event * e)662b15cb3dSCy Schubert void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
min_heap_empty_(min_heap_t * s)672b15cb3dSCy Schubert int min_heap_empty_(min_heap_t* s) { return 0u == s->n; }
min_heap_size_(min_heap_t * s)682b15cb3dSCy Schubert unsigned min_heap_size_(min_heap_t* s) { return s->n; }
min_heap_top_(min_heap_t * s)692b15cb3dSCy Schubert struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
702b15cb3dSCy Schubert 
min_heap_push_(min_heap_t * s,struct event * e)712b15cb3dSCy Schubert int min_heap_push_(min_heap_t* s, struct event* e)
722b15cb3dSCy Schubert {
73*a466cc55SCy Schubert 	if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1))
742b15cb3dSCy Schubert 		return -1;
752b15cb3dSCy Schubert 	min_heap_shift_up_(s, s->n++, e);
762b15cb3dSCy Schubert 	return 0;
772b15cb3dSCy Schubert }
782b15cb3dSCy Schubert 
min_heap_pop_(min_heap_t * s)792b15cb3dSCy Schubert struct event* min_heap_pop_(min_heap_t* s)
802b15cb3dSCy Schubert {
812b15cb3dSCy Schubert 	if (s->n)
822b15cb3dSCy Schubert 	{
832b15cb3dSCy Schubert 		struct event* e = *s->p;
842b15cb3dSCy Schubert 		min_heap_shift_down_(s, 0u, s->p[--s->n]);
852b15cb3dSCy Schubert 		e->ev_timeout_pos.min_heap_idx = -1;
862b15cb3dSCy Schubert 		return e;
872b15cb3dSCy Schubert 	}
882b15cb3dSCy Schubert 	return 0;
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert 
min_heap_elt_is_top_(const struct event * e)912b15cb3dSCy Schubert int min_heap_elt_is_top_(const struct event *e)
922b15cb3dSCy Schubert {
932b15cb3dSCy Schubert 	return e->ev_timeout_pos.min_heap_idx == 0;
942b15cb3dSCy Schubert }
952b15cb3dSCy Schubert 
min_heap_erase_(min_heap_t * s,struct event * e)962b15cb3dSCy Schubert int min_heap_erase_(min_heap_t* s, struct event* e)
972b15cb3dSCy Schubert {
982b15cb3dSCy Schubert 	if (-1 != e->ev_timeout_pos.min_heap_idx)
992b15cb3dSCy Schubert 	{
1002b15cb3dSCy Schubert 		struct event *last = s->p[--s->n];
1012b15cb3dSCy Schubert 		unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
1022b15cb3dSCy Schubert 		/* we replace e with the last element in the heap.  We might need to
1032b15cb3dSCy Schubert 		   shift it upward if it is less than its parent, or downward if it is
1042b15cb3dSCy Schubert 		   greater than one or both its children. Since the children are known
1052b15cb3dSCy Schubert 		   to be less than the parent, it can't need to shift both up and
1062b15cb3dSCy Schubert 		   down. */
1072b15cb3dSCy Schubert 		if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
1082b15cb3dSCy Schubert 			min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
1092b15cb3dSCy Schubert 		else
1102b15cb3dSCy Schubert 			min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
1112b15cb3dSCy Schubert 		e->ev_timeout_pos.min_heap_idx = -1;
1122b15cb3dSCy Schubert 		return 0;
1132b15cb3dSCy Schubert 	}
1142b15cb3dSCy Schubert 	return -1;
1152b15cb3dSCy Schubert }
1162b15cb3dSCy Schubert 
min_heap_adjust_(min_heap_t * s,struct event * e)1172b15cb3dSCy Schubert int min_heap_adjust_(min_heap_t *s, struct event *e)
1182b15cb3dSCy Schubert {
1192b15cb3dSCy Schubert 	if (-1 == e->ev_timeout_pos.min_heap_idx) {
1202b15cb3dSCy Schubert 		return min_heap_push_(s, e);
1212b15cb3dSCy Schubert 	} else {
1222b15cb3dSCy Schubert 		unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
1232b15cb3dSCy Schubert 		/* The position of e has changed; we shift it up or down
1242b15cb3dSCy Schubert 		 * as needed.  We can't need to do both. */
1252b15cb3dSCy Schubert 		if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
1262b15cb3dSCy Schubert 			min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
1272b15cb3dSCy Schubert 		else
1282b15cb3dSCy Schubert 			min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
1292b15cb3dSCy Schubert 		return 0;
1302b15cb3dSCy Schubert 	}
1312b15cb3dSCy Schubert }
1322b15cb3dSCy Schubert 
min_heap_reserve_(min_heap_t * s,unsigned n)1332b15cb3dSCy Schubert int min_heap_reserve_(min_heap_t* s, unsigned n)
1342b15cb3dSCy Schubert {
1352b15cb3dSCy Schubert 	if (s->a < n)
1362b15cb3dSCy Schubert 	{
1372b15cb3dSCy Schubert 		struct event** p;
1382b15cb3dSCy Schubert 		unsigned a = s->a ? s->a * 2 : 8;
1392b15cb3dSCy Schubert 		if (a < n)
1402b15cb3dSCy Schubert 			a = n;
141*a466cc55SCy Schubert #if (SIZE_MAX == UINT32_MAX)
142*a466cc55SCy Schubert 		if (a > SIZE_MAX / sizeof *p)
143*a466cc55SCy Schubert 			return -1;
144*a466cc55SCy Schubert #endif
1452b15cb3dSCy Schubert 		if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
1462b15cb3dSCy Schubert 			return -1;
1472b15cb3dSCy Schubert 		s->p = p;
1482b15cb3dSCy Schubert 		s->a = a;
1492b15cb3dSCy Schubert 	}
1502b15cb3dSCy Schubert 	return 0;
1512b15cb3dSCy Schubert }
1522b15cb3dSCy Schubert 
min_heap_shift_up_unconditional_(min_heap_t * s,unsigned hole_index,struct event * e)1532b15cb3dSCy Schubert void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
1542b15cb3dSCy Schubert {
1552b15cb3dSCy Schubert     unsigned parent = (hole_index - 1) / 2;
1562b15cb3dSCy Schubert     do
1572b15cb3dSCy Schubert     {
1582b15cb3dSCy Schubert 	(s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
1592b15cb3dSCy Schubert 	hole_index = parent;
1602b15cb3dSCy Schubert 	parent = (hole_index - 1) / 2;
1612b15cb3dSCy Schubert     } while (hole_index && min_heap_elem_greater(s->p[parent], e));
1622b15cb3dSCy Schubert     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1632b15cb3dSCy Schubert }
1642b15cb3dSCy Schubert 
min_heap_shift_up_(min_heap_t * s,unsigned hole_index,struct event * e)1652b15cb3dSCy Schubert void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
1662b15cb3dSCy Schubert {
1672b15cb3dSCy Schubert     unsigned parent = (hole_index - 1) / 2;
1682b15cb3dSCy Schubert     while (hole_index && min_heap_elem_greater(s->p[parent], e))
1692b15cb3dSCy Schubert     {
1702b15cb3dSCy Schubert 	(s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
1712b15cb3dSCy Schubert 	hole_index = parent;
1722b15cb3dSCy Schubert 	parent = (hole_index - 1) / 2;
1732b15cb3dSCy Schubert     }
1742b15cb3dSCy Schubert     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1752b15cb3dSCy Schubert }
1762b15cb3dSCy Schubert 
min_heap_shift_down_(min_heap_t * s,unsigned hole_index,struct event * e)1772b15cb3dSCy Schubert void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
1782b15cb3dSCy Schubert {
1792b15cb3dSCy Schubert     unsigned min_child = 2 * (hole_index + 1);
1802b15cb3dSCy Schubert     while (min_child <= s->n)
1812b15cb3dSCy Schubert 	{
1822b15cb3dSCy Schubert 	min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
1832b15cb3dSCy Schubert 	if (!(min_heap_elem_greater(e, s->p[min_child])))
1842b15cb3dSCy Schubert 	    break;
1852b15cb3dSCy Schubert 	(s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index;
1862b15cb3dSCy Schubert 	hole_index = min_child;
1872b15cb3dSCy Schubert 	min_child = 2 * (hole_index + 1);
1882b15cb3dSCy Schubert 	}
1892b15cb3dSCy Schubert     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1902b15cb3dSCy Schubert }
1912b15cb3dSCy Schubert 
1922b15cb3dSCy Schubert #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */
193