xref: /netbsd-src/external/bsd/libevent/dist/minheap-internal.h (revision 7e68cdd7306a8b6c32d6a32c16ba01e5a2ddc083)
1*7e68cdd7Schristos /*	$NetBSD: minheap-internal.h,v 1.4 2021/04/07 03:36:48 christos Exp $	*/
26ecf6635Schristos /*
36ecf6635Schristos  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
46ecf6635Schristos  *
56ecf6635Schristos  * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
66ecf6635Schristos  *
76ecf6635Schristos  * Redistribution and use in source and binary forms, with or without
86ecf6635Schristos  * modification, are permitted provided that the following conditions
96ecf6635Schristos  * are met:
106ecf6635Schristos  * 1. Redistributions of source code must retain the above copyright
116ecf6635Schristos  *    notice, this list of conditions and the following disclaimer.
126ecf6635Schristos  * 2. Redistributions in binary form must reproduce the above copyright
136ecf6635Schristos  *    notice, this list of conditions and the following disclaimer in the
146ecf6635Schristos  *    documentation and/or other materials provided with the distribution.
156ecf6635Schristos  * 3. The name of the author may not be used to endorse or promote products
166ecf6635Schristos  *    derived from this software without specific prior written permission.
176ecf6635Schristos  *
186ecf6635Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
196ecf6635Schristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
206ecf6635Schristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
216ecf6635Schristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
226ecf6635Schristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
236ecf6635Schristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246ecf6635Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256ecf6635Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266ecf6635Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
276ecf6635Schristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286ecf6635Schristos  */
290d738af4Schristos #ifndef MINHEAP_INTERNAL_H_INCLUDED_
300d738af4Schristos #define MINHEAP_INTERNAL_H_INCLUDED_
316ecf6635Schristos 
326ecf6635Schristos #include "event2/event-config.h"
330d738af4Schristos #include "evconfig-private.h"
346ecf6635Schristos #include "event2/event.h"
356ecf6635Schristos #include "event2/event_struct.h"
366ecf6635Schristos #include "event2/util.h"
376ecf6635Schristos #include "util-internal.h"
386ecf6635Schristos #include "mm-internal.h"
396ecf6635Schristos 
406ecf6635Schristos typedef struct min_heap
416ecf6635Schristos {
426ecf6635Schristos 	struct event** p;
436ecf6635Schristos 	unsigned n, a;
446ecf6635Schristos } min_heap_t;
456ecf6635Schristos 
460d738af4Schristos static inline void	     min_heap_ctor_(min_heap_t* s);
470d738af4Schristos static inline void	     min_heap_dtor_(min_heap_t* s);
480d738af4Schristos static inline void	     min_heap_elem_init_(struct event* e);
490d738af4Schristos static inline int	     min_heap_elt_is_top_(const struct event *e);
500d738af4Schristos static inline int	     min_heap_empty_(min_heap_t* s);
510d738af4Schristos static inline unsigned	     min_heap_size_(min_heap_t* s);
520d738af4Schristos static inline struct event*  min_heap_top_(min_heap_t* s);
530d738af4Schristos static inline int	     min_heap_reserve_(min_heap_t* s, unsigned n);
540d738af4Schristos static inline int	     min_heap_push_(min_heap_t* s, struct event* e);
550d738af4Schristos static inline struct event*  min_heap_pop_(min_heap_t* s);
560d738af4Schristos static inline int	     min_heap_adjust_(min_heap_t *s, struct event* e);
570d738af4Schristos static inline int	     min_heap_erase_(min_heap_t* s, struct event* e);
586ecf6635Schristos static inline void	     min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
590d738af4Schristos static inline void	     min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e);
606ecf6635Schristos static inline void	     min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
616ecf6635Schristos 
620d738af4Schristos #define min_heap_elem_greater(a, b) \
630d738af4Schristos 	(evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
646ecf6635Schristos 
min_heap_ctor_(min_heap_t * s)650d738af4Schristos void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
min_heap_dtor_(min_heap_t * s)660d738af4Schristos void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); }
min_heap_elem_init_(struct event * e)670d738af4Schristos void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
min_heap_empty_(min_heap_t * s)680d738af4Schristos int min_heap_empty_(min_heap_t* s) { return 0u == s->n; }
min_heap_size_(min_heap_t * s)690d738af4Schristos unsigned min_heap_size_(min_heap_t* s) { return s->n; }
min_heap_top_(min_heap_t * s)700d738af4Schristos struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
716ecf6635Schristos 
min_heap_push_(min_heap_t * s,struct event * e)720d738af4Schristos int min_heap_push_(min_heap_t* s, struct event* e)
736ecf6635Schristos {
74*7e68cdd7Schristos 	if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1))
756ecf6635Schristos 		return -1;
766ecf6635Schristos 	min_heap_shift_up_(s, s->n++, e);
776ecf6635Schristos 	return 0;
786ecf6635Schristos }
796ecf6635Schristos 
min_heap_pop_(min_heap_t * s)800d738af4Schristos struct event* min_heap_pop_(min_heap_t* s)
816ecf6635Schristos {
826ecf6635Schristos 	if (s->n)
836ecf6635Schristos 	{
846ecf6635Schristos 		struct event* e = *s->p;
856ecf6635Schristos 		min_heap_shift_down_(s, 0u, s->p[--s->n]);
866ecf6635Schristos 		e->ev_timeout_pos.min_heap_idx = -1;
876ecf6635Schristos 		return e;
886ecf6635Schristos 	}
896ecf6635Schristos 	return 0;
906ecf6635Schristos }
916ecf6635Schristos 
min_heap_elt_is_top_(const struct event * e)920d738af4Schristos int min_heap_elt_is_top_(const struct event *e)
936ecf6635Schristos {
946ecf6635Schristos 	return e->ev_timeout_pos.min_heap_idx == 0;
956ecf6635Schristos }
966ecf6635Schristos 
min_heap_erase_(min_heap_t * s,struct event * e)970d738af4Schristos int min_heap_erase_(min_heap_t* s, struct event* e)
986ecf6635Schristos {
996ecf6635Schristos 	if (-1 != e->ev_timeout_pos.min_heap_idx)
1006ecf6635Schristos 	{
1016ecf6635Schristos 		struct event *last = s->p[--s->n];
1026ecf6635Schristos 		unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
1036ecf6635Schristos 		/* we replace e with the last element in the heap.  We might need to
1046ecf6635Schristos 		   shift it upward if it is less than its parent, or downward if it is
1056ecf6635Schristos 		   greater than one or both its children. Since the children are known
1066ecf6635Schristos 		   to be less than the parent, it can't need to shift both up and
1076ecf6635Schristos 		   down. */
1086ecf6635Schristos 		if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
1090d738af4Schristos 			min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
1106ecf6635Schristos 		else
1116ecf6635Schristos 			min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
1126ecf6635Schristos 		e->ev_timeout_pos.min_heap_idx = -1;
1136ecf6635Schristos 		return 0;
1146ecf6635Schristos 	}
1156ecf6635Schristos 	return -1;
1166ecf6635Schristos }
1176ecf6635Schristos 
min_heap_adjust_(min_heap_t * s,struct event * e)1180d738af4Schristos int min_heap_adjust_(min_heap_t *s, struct event *e)
1190d738af4Schristos {
1200d738af4Schristos 	if (-1 == e->ev_timeout_pos.min_heap_idx) {
1210d738af4Schristos 		return min_heap_push_(s, e);
1220d738af4Schristos 	} else {
1230d738af4Schristos 		unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
1240d738af4Schristos 		/* The position of e has changed; we shift it up or down
1250d738af4Schristos 		 * as needed.  We can't need to do both. */
1260d738af4Schristos 		if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
1270d738af4Schristos 			min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
1280d738af4Schristos 		else
1290d738af4Schristos 			min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
1300d738af4Schristos 		return 0;
1310d738af4Schristos 	}
1320d738af4Schristos }
1330d738af4Schristos 
min_heap_reserve_(min_heap_t * s,unsigned n)1340d738af4Schristos int min_heap_reserve_(min_heap_t* s, unsigned n)
1356ecf6635Schristos {
1366ecf6635Schristos 	if (s->a < n)
1376ecf6635Schristos 	{
1386ecf6635Schristos 		struct event** p;
1396ecf6635Schristos 		unsigned a = s->a ? s->a * 2 : 8;
1406ecf6635Schristos 		if (a < n)
1416ecf6635Schristos 			a = n;
142*7e68cdd7Schristos #if (SIZE_MAX == UINT32_MAX)
143*7e68cdd7Schristos 		if (a > SIZE_MAX / sizeof *p)
144*7e68cdd7Schristos 			return -1;
145*7e68cdd7Schristos #endif
1466ecf6635Schristos 		if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
1476ecf6635Schristos 			return -1;
1486ecf6635Schristos 		s->p = p;
1496ecf6635Schristos 		s->a = a;
1506ecf6635Schristos 	}
1516ecf6635Schristos 	return 0;
1526ecf6635Schristos }
1536ecf6635Schristos 
min_heap_shift_up_unconditional_(min_heap_t * s,unsigned hole_index,struct event * e)1540d738af4Schristos void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
1550d738af4Schristos {
1560d738af4Schristos     unsigned parent = (hole_index - 1) / 2;
1570d738af4Schristos     do
1580d738af4Schristos     {
1590d738af4Schristos 	(s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
1600d738af4Schristos 	hole_index = parent;
1610d738af4Schristos 	parent = (hole_index - 1) / 2;
1620d738af4Schristos     } while (hole_index && min_heap_elem_greater(s->p[parent], e));
1630d738af4Schristos     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1640d738af4Schristos }
1650d738af4Schristos 
min_heap_shift_up_(min_heap_t * s,unsigned hole_index,struct event * e)1660d738af4Schristos void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
1676ecf6635Schristos {
1686ecf6635Schristos     unsigned parent = (hole_index - 1) / 2;
1696ecf6635Schristos     while (hole_index && min_heap_elem_greater(s->p[parent], e))
1706ecf6635Schristos     {
1716ecf6635Schristos 	(s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
1726ecf6635Schristos 	hole_index = parent;
1736ecf6635Schristos 	parent = (hole_index - 1) / 2;
1746ecf6635Schristos     }
1756ecf6635Schristos     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1766ecf6635Schristos }
1776ecf6635Schristos 
min_heap_shift_down_(min_heap_t * s,unsigned hole_index,struct event * e)17864b3fac0Sjoerg static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
1796ecf6635Schristos {
1806ecf6635Schristos     unsigned min_child = 2 * (hole_index + 1);
1816ecf6635Schristos     while (min_child <= s->n)
1826ecf6635Schristos 	{
1836ecf6635Schristos 	min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
1846ecf6635Schristos 	if (!(min_heap_elem_greater(e, s->p[min_child])))
1856ecf6635Schristos 	    break;
1866ecf6635Schristos 	(s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index;
1876ecf6635Schristos 	hole_index = min_child;
1886ecf6635Schristos 	min_child = 2 * (hole_index + 1);
1896ecf6635Schristos 	}
1906ecf6635Schristos     (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
1916ecf6635Schristos }
1926ecf6635Schristos 
1930d738af4Schristos #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */
194