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