Always evaluate BT_ASSERT(); add BT_ASSERT_DBG() for debug mode only
[babeltrace.git] / src / 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
91d81473 26#include "common/macros.h"
578e048b 27#include "common/assert.h"
1eb0c69c
MD
28#include <errno.h>
29#include <stdlib.h>
30#include <string.h>
31
578e048b
MJ
32#include "prio-heap.h"
33
eacd552c
MD
34#ifdef DEBUG_HEAP
35void check_heap(const struct ptr_heap *heap)
36{
37 size_t i;
38
39 if (!heap->len)
40 return;
41
42 for (i = 1; i < heap->len; i++)
98b15851 43 BT_ASSERT_DBG(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
eacd552c
MD
44}
45#endif
46
557255e5 47static
1eb0c69c
MD
48size_t parent(size_t i)
49{
eacd552c 50 return (i - 1) >> 1;
1eb0c69c
MD
51}
52
53static
54size_t left(size_t i)
55{
eacd552c 56 return (i << 1) + 1;
1eb0c69c
MD
57}
58
59static
60size_t right(size_t i)
61{
eacd552c 62 return (i << 1) + 2;
1eb0c69c
MD
63}
64
557255e5
MD
65/*
66 * Copy of heap->ptrs pointer is invalid after heap_grow.
67 */
1eb0c69c
MD
68static
69int heap_grow(struct ptr_heap *heap, size_t new_len)
70{
71 void **new_ptrs;
72
91d81473 73 if (G_LIKELY(heap->alloc_len >= new_len))
1eb0c69c
MD
74 return 0;
75
91d81473 76 heap->alloc_len = bt_max_t(size_t, new_len, heap->alloc_len << 1);
1eb0c69c 77 new_ptrs = calloc(heap->alloc_len, sizeof(void *));
91d81473 78 if (G_UNLIKELY(!new_ptrs))
1eb0c69c 79 return -ENOMEM;
91d81473 80 if (G_LIKELY(heap->ptrs))
1eb0c69c
MD
81 memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
82 free(heap->ptrs);
83 heap->ptrs = new_ptrs;
84 return 0;
85}
86
87static
88int heap_set_len(struct ptr_heap *heap, size_t new_len)
89{
90 int ret;
91
92 ret = heap_grow(heap, new_len);
91d81473 93 if (G_UNLIKELY(ret))
1eb0c69c
MD
94 return ret;
95 heap->len = new_len;
96 return 0;
97}
98
dd06413f 99int bt_heap_init(struct ptr_heap *heap, size_t alloc_len,
1eb0c69c
MD
100 int gt(void *a, void *b))
101{
102 heap->ptrs = NULL;
103 heap->len = 0;
104 heap->alloc_len = 0;
105 heap->gt = gt;
106 /*
107 * Minimum size allocated is 1 entry to ensure memory allocation
dd06413f 108 * never fails within bt_heap_replace_max.
1eb0c69c 109 */
91d81473 110 return heap_grow(heap, bt_max_t(size_t, 1, alloc_len));
1eb0c69c
MD
111}
112
dd06413f 113void bt_heap_free(struct ptr_heap *heap)
1eb0c69c
MD
114{
115 free(heap->ptrs);
116}
117
118static void heapify(struct ptr_heap *heap, size_t i)
119{
120 void **ptrs = heap->ptrs;
121 size_t l, r, largest;
122
123 for (;;) {
eacd552c
MD
124 void *tmp;
125
1eb0c69c
MD
126 l = left(i);
127 r = right(i);
eacd552c 128 if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
1eb0c69c
MD
129 largest = l;
130 else
131 largest = i;
eacd552c 132 if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
1eb0c69c 133 largest = r;
91d81473 134 if (G_UNLIKELY(largest == i))
1eb0c69c 135 break;
eacd552c
MD
136 tmp = ptrs[i];
137 ptrs[i] = ptrs[largest];
138 ptrs[largest] = tmp;
139 i = largest;
1eb0c69c 140 }
eacd552c 141 check_heap(heap);
1eb0c69c
MD
142}
143
dd06413f 144void *bt_heap_replace_max(struct ptr_heap *heap, void *p)
1eb0c69c
MD
145{
146 void *res;
1eb0c69c 147
91d81473 148 if (G_UNLIKELY(!heap->len)) {
1eb0c69c 149 (void) heap_set_len(heap, 1);
557255e5 150 heap->ptrs[0] = p;
eacd552c 151 check_heap(heap);
1eb0c69c
MD
152 return NULL;
153 }
154
155 /* Replace the current max and heapify */
557255e5
MD
156 res = heap->ptrs[0];
157 heap->ptrs[0] = p;
1eb0c69c
MD
158 heapify(heap, 0);
159 return res;
160}
161
dd06413f 162int bt_heap_insert(struct ptr_heap *heap, void *p)
1eb0c69c 163{
557255e5
MD
164 void **ptrs;
165 size_t pos;
1eb0c69c
MD
166 int ret;
167
168 ret = heap_set_len(heap, heap->len + 1);
91d81473 169 if (G_UNLIKELY(ret))
1eb0c69c 170 return ret;
557255e5 171 ptrs = heap->ptrs;
557255e5 172 pos = heap->len - 1;
eacd552c
MD
173 while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
174 /* Move parent down until we find the right spot */
175 ptrs[pos] = ptrs[parent(pos)];
176 pos = parent(pos);
557255e5 177 }
eacd552c
MD
178 ptrs[pos] = p;
179 check_heap(heap);
1eb0c69c
MD
180 return 0;
181}
182
dd06413f 183void *bt_heap_remove(struct ptr_heap *heap)
1eb0c69c 184{
1eb0c69c
MD
185 switch (heap->len) {
186 case 0:
187 return NULL;
188 case 1:
189 (void) heap_set_len(heap, 0);
557255e5 190 return heap->ptrs[0];
1eb0c69c
MD
191 }
192 /* Shrink, replace the current max by previous last entry and heapify */
193 heap_set_len(heap, heap->len - 1);
eacd552c 194 /* len changed. previous last entry is at heap->len */
dd06413f 195 return bt_heap_replace_max(heap, heap->ptrs[heap->len]);
1eb0c69c
MD
196}
197
dd06413f 198void *bt_heap_cherrypick(struct ptr_heap *heap, void *p)
1eb0c69c 199{
1eb0c69c
MD
200 size_t pos, len = heap->len;
201
202 for (pos = 0; pos < len; pos++)
91d81473 203 if (G_UNLIKELY(heap->ptrs[pos] == p))
1eb0c69c
MD
204 goto found;
205 return NULL;
206found:
91d81473 207 if (G_UNLIKELY(heap->len == 1)) {
1eb0c69c 208 (void) heap_set_len(heap, 0);
eacd552c 209 check_heap(heap);
557255e5 210 return heap->ptrs[0];
1eb0c69c
MD
211 }
212 /* Replace p with previous last entry and heapify. */
213 heap_set_len(heap, heap->len - 1);
eacd552c
MD
214 /* len changed. previous last entry is at heap->len */
215 heap->ptrs[pos] = heap->ptrs[heap->len];
1eb0c69c
MD
216 heapify(heap, pos);
217 return p;
218}
23a151f0 219
dd06413f 220int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src)
23a151f0
JD
221{
222 int ret;
223
dd06413f 224 ret = bt_heap_init(dst, src->alloc_len, src->gt);
23a151f0
JD
225 if (ret < 0)
226 goto end;
227
228 ret = heap_set_len(dst, src->len);
229 if (ret < 0)
230 goto end;
231
232 memcpy(dst->ptrs, src->ptrs, src->len * sizeof(void *));
233
234end:
235 return ret;
236}
This page took 0.081958 seconds and 4 git commands to generate.