lib: graph: add "self" and some "private" APIs
[babeltrace.git] / lib / prio_heap / prio_heap.c
CommitLineData
1eb0c69c 1/*
1eb0c69c
MD
2 * Static-sized priority heap containing pointers. Based on CLRS,
3 * chapter 6.
4 *
5 * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
c462e188
MD
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
1eb0c69c
MD
24 */
25
3d9990ac 26#include <babeltrace/prio-heap-internal.h>
96e1cf26 27#include <babeltrace/babeltrace-internal.h>
f6ccaed9 28#include <babeltrace/assert-internal.h>
1eb0c69c
MD
29#include <errno.h>
30#include <stdlib.h>
31#include <string.h>
32
eacd552c
MD
33#ifdef DEBUG_HEAP
34void check_heap(const struct ptr_heap *heap)
35{
36 size_t i;
37
38 if (!heap->len)
39 return;
40
41 for (i = 1; i < heap->len; i++)
f6ccaed9 42 BT_ASSERT(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
eacd552c
MD
43}
44#endif
45
557255e5 46static
1eb0c69c
MD
47size_t parent(size_t i)
48{
eacd552c 49 return (i - 1) >> 1;
1eb0c69c
MD
50}
51
52static
53size_t left(size_t i)
54{
eacd552c 55 return (i << 1) + 1;
1eb0c69c
MD
56}
57
58static
59size_t right(size_t i)
60{
eacd552c 61 return (i << 1) + 2;
1eb0c69c
MD
62}
63
557255e5
MD
64/*
65 * Copy of heap->ptrs pointer is invalid after heap_grow.
66 */
1eb0c69c
MD
67static
68int heap_grow(struct ptr_heap *heap, size_t new_len)
69{
70 void **new_ptrs;
71
96e1cf26 72 if (likely(heap->alloc_len >= new_len))
1eb0c69c
MD
73 return 0;
74
75 heap->alloc_len = max_t(size_t, new_len, heap->alloc_len << 1);
76 new_ptrs = calloc(heap->alloc_len, sizeof(void *));
96e1cf26 77 if (unlikely(!new_ptrs))
1eb0c69c 78 return -ENOMEM;
96e1cf26 79 if (likely(heap->ptrs))
1eb0c69c
MD
80 memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
81 free(heap->ptrs);
82 heap->ptrs = new_ptrs;
83 return 0;
84}
85
86static
87int heap_set_len(struct ptr_heap *heap, size_t new_len)
88{
89 int ret;
90
91 ret = heap_grow(heap, new_len);
96e1cf26 92 if (unlikely(ret))
1eb0c69c
MD
93 return ret;
94 heap->len = new_len;
95 return 0;
96}
97
dd06413f 98int bt_heap_init(struct ptr_heap *heap, size_t alloc_len,
1eb0c69c
MD
99 int gt(void *a, void *b))
100{
101 heap->ptrs = NULL;
102 heap->len = 0;
103 heap->alloc_len = 0;
104 heap->gt = gt;
105 /*
106 * Minimum size allocated is 1 entry to ensure memory allocation
dd06413f 107 * never fails within bt_heap_replace_max.
1eb0c69c
MD
108 */
109 return heap_grow(heap, max_t(size_t, 1, alloc_len));
110}
111
dd06413f 112void bt_heap_free(struct ptr_heap *heap)
1eb0c69c
MD
113{
114 free(heap->ptrs);
115}
116
117static void heapify(struct ptr_heap *heap, size_t i)
118{
119 void **ptrs = heap->ptrs;
120 size_t l, r, largest;
121
122 for (;;) {
eacd552c
MD
123 void *tmp;
124
1eb0c69c
MD
125 l = left(i);
126 r = right(i);
eacd552c 127 if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
1eb0c69c
MD
128 largest = l;
129 else
130 largest = i;
eacd552c 131 if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
1eb0c69c 132 largest = r;
96e1cf26 133 if (unlikely(largest == i))
1eb0c69c 134 break;
eacd552c
MD
135 tmp = ptrs[i];
136 ptrs[i] = ptrs[largest];
137 ptrs[largest] = tmp;
138 i = largest;
1eb0c69c 139 }
eacd552c 140 check_heap(heap);
1eb0c69c
MD
141}
142
dd06413f 143void *bt_heap_replace_max(struct ptr_heap *heap, void *p)
1eb0c69c
MD
144{
145 void *res;
1eb0c69c 146
96e1cf26 147 if (unlikely(!heap->len)) {
1eb0c69c 148 (void) heap_set_len(heap, 1);
557255e5 149 heap->ptrs[0] = p;
eacd552c 150 check_heap(heap);
1eb0c69c
MD
151 return NULL;
152 }
153
154 /* Replace the current max and heapify */
557255e5
MD
155 res = heap->ptrs[0];
156 heap->ptrs[0] = p;
1eb0c69c
MD
157 heapify(heap, 0);
158 return res;
159}
160
dd06413f 161int bt_heap_insert(struct ptr_heap *heap, void *p)
1eb0c69c 162{
557255e5
MD
163 void **ptrs;
164 size_t pos;
1eb0c69c
MD
165 int ret;
166
167 ret = heap_set_len(heap, heap->len + 1);
96e1cf26 168 if (unlikely(ret))
1eb0c69c 169 return ret;
557255e5 170 ptrs = heap->ptrs;
557255e5 171 pos = heap->len - 1;
eacd552c
MD
172 while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
173 /* Move parent down until we find the right spot */
174 ptrs[pos] = ptrs[parent(pos)];
175 pos = parent(pos);
557255e5 176 }
eacd552c
MD
177 ptrs[pos] = p;
178 check_heap(heap);
1eb0c69c
MD
179 return 0;
180}
181
dd06413f 182void *bt_heap_remove(struct ptr_heap *heap)
1eb0c69c 183{
1eb0c69c
MD
184 switch (heap->len) {
185 case 0:
186 return NULL;
187 case 1:
188 (void) heap_set_len(heap, 0);
557255e5 189 return heap->ptrs[0];
1eb0c69c
MD
190 }
191 /* Shrink, replace the current max by previous last entry and heapify */
192 heap_set_len(heap, heap->len - 1);
eacd552c 193 /* len changed. previous last entry is at heap->len */
dd06413f 194 return bt_heap_replace_max(heap, heap->ptrs[heap->len]);
1eb0c69c
MD
195}
196
dd06413f 197void *bt_heap_cherrypick(struct ptr_heap *heap, void *p)
1eb0c69c 198{
1eb0c69c
MD
199 size_t pos, len = heap->len;
200
201 for (pos = 0; pos < len; pos++)
96e1cf26 202 if (unlikely(heap->ptrs[pos] == p))
1eb0c69c
MD
203 goto found;
204 return NULL;
205found:
96e1cf26 206 if (unlikely(heap->len == 1)) {
1eb0c69c 207 (void) heap_set_len(heap, 0);
eacd552c 208 check_heap(heap);
557255e5 209 return heap->ptrs[0];
1eb0c69c
MD
210 }
211 /* Replace p with previous last entry and heapify. */
212 heap_set_len(heap, heap->len - 1);
eacd552c
MD
213 /* len changed. previous last entry is at heap->len */
214 heap->ptrs[pos] = heap->ptrs[heap->len];
1eb0c69c
MD
215 heapify(heap, pos);
216 return p;
217}
23a151f0 218
dd06413f 219int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src)
23a151f0
JD
220{
221 int ret;
222
dd06413f 223 ret = bt_heap_init(dst, src->alloc_len, src->gt);
23a151f0
JD
224 if (ret < 0)
225 goto end;
226
227 ret = heap_set_len(dst, src->len);
228 if (ret < 0)
229 goto end;
230
231 memcpy(dst->ptrs, src->ptrs, src->len * sizeof(void *));
232
233end:
234 return ret;
235}
This page took 0.055579 seconds and 4 git commands to generate.