1169321c9SNick Mathewson /*
2e49e2891SNick Mathewson * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
3b85b710cSNick Mathewson *
4169321c9SNick Mathewson * Copyright (c) 2006 Maxim Yegorushkin <[email protected]>
5169321c9SNick Mathewson *
6169321c9SNick Mathewson * Redistribution and use in source and binary forms, with or without
7169321c9SNick Mathewson * modification, are permitted provided that the following conditions
8169321c9SNick Mathewson * are met:
9169321c9SNick Mathewson * 1. Redistributions of source code must retain the above copyright
10169321c9SNick Mathewson * notice, this list of conditions and the following disclaimer.
11169321c9SNick Mathewson * 2. Redistributions in binary form must reproduce the above copyright
12169321c9SNick Mathewson * notice, this list of conditions and the following disclaimer in the
13169321c9SNick Mathewson * documentation and/or other materials provided with the distribution.
14169321c9SNick Mathewson * 3. The name of the author may not be used to endorse or promote products
15169321c9SNick Mathewson * derived from this software without specific prior written permission.
16169321c9SNick Mathewson *
17169321c9SNick Mathewson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18169321c9SNick Mathewson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19169321c9SNick Mathewson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20169321c9SNick Mathewson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21169321c9SNick Mathewson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22169321c9SNick Mathewson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23169321c9SNick Mathewson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24169321c9SNick Mathewson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25169321c9SNick Mathewson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26169321c9SNick Mathewson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27169321c9SNick Mathewson */
283f8c7cd0SNick Mathewson #ifndef MINHEAP_INTERNAL_H_INCLUDED_
293f8c7cd0SNick Mathewson #define MINHEAP_INTERNAL_H_INCLUDED_
30169321c9SNick Mathewson
31ec347b92SNick Mathewson #include "event2/event-config.h"
320915ca0aSKevin Bowling #include "evconfig-private.h"
33169321c9SNick Mathewson #include "event2/event.h"
34169321c9SNick Mathewson #include "event2/event_struct.h"
35169321c9SNick Mathewson #include "event2/util.h"
36ebf29455SNick Mathewson #include "util-internal.h"
37a5276180SNick Mathewson #include "mm-internal.h"
38169321c9SNick Mathewson
39169321c9SNick Mathewson typedef struct min_heap
40169321c9SNick Mathewson {
41169321c9SNick Mathewson struct event** p;
4218104973SAzat Khuzhin unsigned n, a;
43169321c9SNick Mathewson } min_heap_t;
44169321c9SNick Mathewson
458ac3c4c2SNick Mathewson static inline void min_heap_ctor_(min_heap_t* s);
468ac3c4c2SNick Mathewson static inline void min_heap_dtor_(min_heap_t* s);
478ac3c4c2SNick Mathewson static inline void min_heap_elem_init_(struct event* e);
488ac3c4c2SNick Mathewson static inline int min_heap_elt_is_top_(const struct event *e);
498ac3c4c2SNick Mathewson static inline int min_heap_empty_(min_heap_t* s);
5018104973SAzat Khuzhin static inline unsigned min_heap_size_(min_heap_t* s);
518ac3c4c2SNick Mathewson static inline struct event* min_heap_top_(min_heap_t* s);
5218104973SAzat Khuzhin static inline int min_heap_reserve_(min_heap_t* s, unsigned n);
538ac3c4c2SNick Mathewson static inline int min_heap_push_(min_heap_t* s, struct event* e);
548ac3c4c2SNick Mathewson static inline struct event* min_heap_pop_(min_heap_t* s);
558ac3c4c2SNick Mathewson static inline int min_heap_adjust_(min_heap_t *s, struct event* e);
568ac3c4c2SNick Mathewson static inline int min_heap_erase_(min_heap_t* s, struct event* e);
5718104973SAzat Khuzhin static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
5818104973SAzat Khuzhin static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e);
5918104973SAzat Khuzhin static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
60169321c9SNick Mathewson
61dd5189b1SNick Mathewson #define min_heap_elem_greater(a, b) \
62dd5189b1SNick Mathewson (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
63169321c9SNick Mathewson
min_heap_ctor_(min_heap_t * s)648ac3c4c2SNick Mathewson void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
min_heap_dtor_(min_heap_t * s)658ac3c4c2SNick Mathewson void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); }
min_heap_elem_init_(struct event * e)6618104973SAzat Khuzhin void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
min_heap_empty_(min_heap_t * s)6718104973SAzat Khuzhin int min_heap_empty_(min_heap_t* s) { return 0u == s->n; }
min_heap_size_(min_heap_t * s)6818104973SAzat Khuzhin unsigned min_heap_size_(min_heap_t* s) { return s->n; }
min_heap_top_(min_heap_t * s)698ac3c4c2SNick Mathewson struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
70169321c9SNick Mathewson
min_heap_push_(min_heap_t * s,struct event * e)718ac3c4c2SNick Mathewson int min_heap_push_(min_heap_t* s, struct event* e)
72169321c9SNick Mathewson {
73*8c899768STobias Stoeckmann if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1))
74169321c9SNick Mathewson return -1;
75169321c9SNick Mathewson min_heap_shift_up_(s, s->n++, e);
76169321c9SNick Mathewson return 0;
77169321c9SNick Mathewson }
78169321c9SNick Mathewson
min_heap_pop_(min_heap_t * s)798ac3c4c2SNick Mathewson struct event* min_heap_pop_(min_heap_t* s)
80169321c9SNick Mathewson {
81169321c9SNick Mathewson if (s->n)
82169321c9SNick Mathewson {
83169321c9SNick Mathewson struct event* e = *s->p;
8418104973SAzat Khuzhin min_heap_shift_down_(s, 0u, s->p[--s->n]);
8518104973SAzat Khuzhin e->ev_timeout_pos.min_heap_idx = -1;
86169321c9SNick Mathewson return e;
87169321c9SNick Mathewson }
88169321c9SNick Mathewson return 0;
89169321c9SNick Mathewson }
90169321c9SNick Mathewson
min_heap_elt_is_top_(const struct event * e)918ac3c4c2SNick Mathewson int min_heap_elt_is_top_(const struct event *e)
92ba8a1771SNick Mathewson {
93693c24efSNick Mathewson return e->ev_timeout_pos.min_heap_idx == 0;
94ba8a1771SNick Mathewson }
95ba8a1771SNick Mathewson
min_heap_erase_(min_heap_t * s,struct event * e)968ac3c4c2SNick Mathewson int min_heap_erase_(min_heap_t* s, struct event* e)
97169321c9SNick Mathewson {
9818104973SAzat Khuzhin if (-1 != e->ev_timeout_pos.min_heap_idx)
99169321c9SNick Mathewson {
1008b7a3b36SNick Mathewson struct event *last = s->p[--s->n];
10118104973SAzat Khuzhin unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
1028b7a3b36SNick Mathewson /* we replace e with the last element in the heap. We might need to
1038b7a3b36SNick Mathewson shift it upward if it is less than its parent, or downward if it is
1048b7a3b36SNick Mathewson greater than one or both its children. Since the children are known
1058b7a3b36SNick Mathewson to be less than the parent, it can't need to shift both up and
1068b7a3b36SNick Mathewson down. */
107693c24efSNick Mathewson if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
108dd5189b1SNick Mathewson min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
1098b7a3b36SNick Mathewson else
110693c24efSNick Mathewson min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
11118104973SAzat Khuzhin e->ev_timeout_pos.min_heap_idx = -1;
112169321c9SNick Mathewson return 0;
113169321c9SNick Mathewson }
114169321c9SNick Mathewson return -1;
115169321c9SNick Mathewson }
116169321c9SNick Mathewson
min_heap_adjust_(min_heap_t * s,struct event * e)1178ac3c4c2SNick Mathewson int min_heap_adjust_(min_heap_t *s, struct event *e)
118e47042feSNick Mathewson {
11918104973SAzat Khuzhin if (-1 == e->ev_timeout_pos.min_heap_idx) {
1208ac3c4c2SNick Mathewson return min_heap_push_(s, e);
121e47042feSNick Mathewson } else {
12218104973SAzat Khuzhin unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
123e47042feSNick Mathewson /* The position of e has changed; we shift it up or down
124e47042feSNick Mathewson * as needed. We can't need to do both. */
125e47042feSNick Mathewson if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
126dd5189b1SNick Mathewson min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
127e47042feSNick Mathewson else
128e47042feSNick Mathewson min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
129e47042feSNick Mathewson return 0;
130e47042feSNick Mathewson }
131e47042feSNick Mathewson }
132e47042feSNick Mathewson
min_heap_reserve_(min_heap_t * s,unsigned n)13318104973SAzat Khuzhin int min_heap_reserve_(min_heap_t* s, unsigned n)
134169321c9SNick Mathewson {
135169321c9SNick Mathewson if (s->a < n)
136169321c9SNick Mathewson {
137169321c9SNick Mathewson struct event** p;
13818104973SAzat Khuzhin unsigned a = s->a ? s->a * 2 : 8;
139169321c9SNick Mathewson if (a < n)
140169321c9SNick Mathewson a = n;
141*8c899768STobias Stoeckmann #if (SIZE_MAX == UINT32_MAX)
142*8c899768STobias Stoeckmann if (a > SIZE_MAX / sizeof *p)
143*8c899768STobias Stoeckmann return -1;
144*8c899768STobias Stoeckmann #endif
145a5276180SNick Mathewson if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
146169321c9SNick Mathewson return -1;
147169321c9SNick Mathewson s->p = p;
148169321c9SNick Mathewson s->a = a;
149169321c9SNick Mathewson }
150169321c9SNick Mathewson return 0;
151169321c9SNick Mathewson }
152169321c9SNick Mathewson
min_heap_shift_up_unconditional_(min_heap_t * s,unsigned hole_index,struct event * e)15318104973SAzat Khuzhin void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
154dd5189b1SNick Mathewson {
15518104973SAzat Khuzhin unsigned parent = (hole_index - 1) / 2;
156dd5189b1SNick Mathewson do
157dd5189b1SNick Mathewson {
158dd5189b1SNick Mathewson (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
159dd5189b1SNick Mathewson hole_index = parent;
160dd5189b1SNick Mathewson parent = (hole_index - 1) / 2;
161dd5189b1SNick Mathewson } while (hole_index && min_heap_elem_greater(s->p[parent], e));
162dd5189b1SNick Mathewson (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
163dd5189b1SNick Mathewson }
164dd5189b1SNick Mathewson
min_heap_shift_up_(min_heap_t * s,unsigned hole_index,struct event * e)16518104973SAzat Khuzhin void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
166169321c9SNick Mathewson {
16718104973SAzat Khuzhin unsigned parent = (hole_index - 1) / 2;
168169321c9SNick Mathewson while (hole_index && min_heap_elem_greater(s->p[parent], e))
169169321c9SNick Mathewson {
170693c24efSNick Mathewson (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
171169321c9SNick Mathewson hole_index = parent;
172169321c9SNick Mathewson parent = (hole_index - 1) / 2;
173169321c9SNick Mathewson }
174693c24efSNick Mathewson (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
175169321c9SNick Mathewson }
176169321c9SNick Mathewson
min_heap_shift_down_(min_heap_t * s,unsigned hole_index,struct event * e)17718104973SAzat Khuzhin void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
178169321c9SNick Mathewson {
17918104973SAzat Khuzhin unsigned min_child = 2 * (hole_index + 1);
180169321c9SNick Mathewson while (min_child <= s->n)
181169321c9SNick Mathewson {
182169321c9SNick Mathewson min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
183169321c9SNick Mathewson if (!(min_heap_elem_greater(e, s->p[min_child])))
184169321c9SNick Mathewson break;
185693c24efSNick Mathewson (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index;
186169321c9SNick Mathewson hole_index = min_child;
187169321c9SNick Mathewson min_child = 2 * (hole_index + 1);
188169321c9SNick Mathewson }
1897204b916SNick Mathewson (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
190169321c9SNick Mathewson }
191169321c9SNick Mathewson
1923f8c7cd0SNick Mathewson #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */
193