-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbh.c
133 lines (102 loc) · 2.3 KB
/
bh.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* Simple Binary Heap with Wait Queue
*
* Copyright (c) 2015-2023 Alexei A. Smekalkine
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <data/bh.h>
/* heap based on full binary tree packed into array */
#define root (0)
#define left(i) (2 * (i) + 1)
#define right(i) (2 * (i) + 2)
#define parent(i) (((i) - 1) / 2)
void bh_init (struct bh *o, int (*gt) (const void *a, const void *b))
{
o->gt = gt;
o->avail = o->tail = o->count = 0;
o->pool = NULL;
}
void bh_fini (struct bh *o, void (*item_free) (void *o))
{
size_t i;
if (item_free != NULL)
for (i = 0; i < o->tail; ++i)
item_free (o->pool[i]);
free (o->pool);
}
void *bh_top (struct bh *o)
{
return (o->count > 0) ? o->pool[0] : NULL;
}
static int bh_resize (struct bh *o)
{
size_t next = (o->avail < 8) ? 8 : o->avail * 2;
void *pool;
if (o->tail < o->avail)
return 1;
if (sizeof (o->pool[0]) * next < sizeof (o->pool[0]) * o->avail) {
errno = ENOMEM;
return 0;
}
if ((pool = realloc (o->pool, sizeof (o->pool[0]) * next)) == NULL)
return 0;
o->pool = pool;
o->avail = next;
return 1;
}
static void bh_bubble_up (struct bh *o, size_t i)
{
void *x = o->pool[i];
for (; i > root && o->gt (x, o->pool[parent (i)]); i = parent (i))
o->pool[i] = o->pool[parent (i)]; /* pull down */
o->pool[i] = x;
}
static size_t bh_max_child (struct bh *o, size_t i)
{
size_t l = left (i), r = right (i);
return l >= o->count ? 0 : /* root cannot be child of any node */
r >= o->count ? l :
o->gt (o->pool [l], o->pool [r]) ? l : r;
}
static void bh_bubble_down (struct bh *o, size_t i)
{
void *x = o->pool[i];
size_t child;
for (
;
(child = bh_max_child (o, i)) != 0 &&
o->gt (o->pool [child], x);
i = child
)
o->pool[i] = o->pool[child]; /* pull up */
o->pool[i] = x;
}
void bh_commit (struct bh *o)
{
for (; o->count < o->tail; ++o->count)
bh_bubble_up (o, o->count);
}
int bh_push (struct bh *o, void *x, int nowait)
{
if (o->tail >= o->avail && (nowait || !bh_resize (o)))
return 0;
o->pool[o->tail++] = x;
if (!nowait)
bh_commit (o);
return 1;
}
void *bh_pop (struct bh *o)
{
void *x;
bh_commit (o);
if (o->count == 0)
return NULL;
x = o->pool[0];
o->pool[0] = o->pool[o->tail = --o->count];
bh_bubble_down (o, 0);
return x;
}