Coverage Report

Created: 2025-07-18 07:02

/src/bind9/lib/isc/heap.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file
15
 * Heap implementation of priority queues adapted from the following:
16
 *
17
 *  \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
18
 *  MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
19
 *
20
 *  \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
21
 *  ISBN 0-201-06673-4, chapter 11.
22
 */
23
24
#include <stdbool.h>
25
26
#include <isc/heap.h>
27
#include <isc/magic.h>
28
#include <isc/mem.h>
29
#include <isc/overflow.h>
30
#include <isc/string.h> /* Required for memmove. */
31
#include <isc/util.h>
32
33
/*@{*/
34
/*%
35
 * Note: to make heap_parent and heap_left easy to compute, the first
36
 * element of the heap array is not used; i.e. heap subscripts are 1-based,
37
 * not 0-based.  The parent is index/2, and the left-child is index*2.
38
 * The right child is index*2+1.
39
 */
40
0
#define heap_parent(i) ((i) >> 1)
41
0
#define heap_left(i)   ((i) << 1)
42
/*@}*/
43
44
0
#define SIZE_INCREMENT 1024
45
46
0
#define HEAP_MAGIC    ISC_MAGIC('H', 'E', 'A', 'P')
47
#define VALID_HEAP(h) ISC_MAGIC_VALID(h, HEAP_MAGIC)
48
49
/*%
50
 * When the heap is in a consistent state, the following invariant
51
 * holds true: for every element i > 1, heap_parent(i) has a priority
52
 * higher than or equal to that of i.
53
 */
54
#define HEAPCONDITION(i) \
55
  ((i) == 1 ||     \
56
   !heap->compare(heap->array[(i)], heap->array[heap_parent(i)]))
57
58
/*% ISC heap structure. */
59
struct isc_heap {
60
  unsigned int magic;
61
  isc_mem_t *mctx;
62
  unsigned int size;
63
  unsigned int size_increment;
64
  unsigned int last;
65
  void **array;
66
  isc_heapcompare_t compare;
67
  isc_heapindex_t index;
68
};
69
70
#ifdef ISC_HEAP_CHECK
71
static void
72
heap_check(isc_heap_t *heap) {
73
  unsigned int i;
74
  for (i = 1; i <= heap->last; i++) {
75
    INSIST(HEAPCONDITION(i));
76
  }
77
}
78
#else /* ifdef ISC_HEAP_CHECK */
79
0
#define heap_check(x) (void)0
80
#endif /* ifdef ISC_HEAP_CHECK */
81
82
void
83
isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare, isc_heapindex_t idx,
84
0
    unsigned int size_increment, isc_heap_t **heapp) {
85
0
  isc_heap_t *heap;
86
87
0
  REQUIRE(heapp != NULL && *heapp == NULL);
88
0
  REQUIRE(compare != NULL);
89
90
0
  heap = isc_mem_get(mctx, sizeof(*heap));
91
0
  heap->magic = HEAP_MAGIC;
92
0
  heap->size = 0;
93
0
  heap->mctx = NULL;
94
0
  isc_mem_attach(mctx, &heap->mctx);
95
0
  if (size_increment == 0) {
96
0
    heap->size_increment = SIZE_INCREMENT;
97
0
  } else {
98
0
    heap->size_increment = size_increment;
99
0
  }
100
0
  heap->last = 0;
101
0
  heap->array = NULL;
102
0
  heap->compare = compare;
103
0
  heap->index = idx;
104
105
0
  *heapp = heap;
106
0
}
107
108
void
109
0
isc_heap_destroy(isc_heap_t **heapp) {
110
0
  isc_heap_t *heap;
111
112
0
  REQUIRE(heapp != NULL);
113
0
  heap = *heapp;
114
0
  *heapp = NULL;
115
0
  REQUIRE(VALID_HEAP(heap));
116
117
0
  if (heap->array != NULL) {
118
0
    isc_mem_cput(heap->mctx, heap->array, heap->size,
119
0
           sizeof(void *));
120
0
  }
121
0
  heap->magic = 0;
122
0
  isc_mem_putanddetach(&heap->mctx, heap, sizeof(*heap));
123
0
}
124
125
static void
126
0
resize(isc_heap_t *heap) {
127
0
  unsigned int new_size, new_bytes, old_bytes;
128
129
0
  REQUIRE(VALID_HEAP(heap));
130
131
0
  new_size = ISC_CHECKED_ADD(heap->size, heap->size_increment);
132
0
  new_bytes = ISC_CHECKED_MUL(new_size, sizeof(void *));
133
0
  old_bytes = ISC_CHECKED_MUL(heap->size, sizeof(void *));
134
135
0
  heap->size = new_size;
136
0
  heap->array = isc_mem_creget(heap->mctx, heap->array, old_bytes,
137
0
             new_bytes, sizeof(char));
138
0
}
139
140
static void
141
0
float_up(isc_heap_t *heap, unsigned int i, void *elt) {
142
0
  unsigned int p;
143
144
0
  for (p = heap_parent(i); i > 1 && heap->compare(elt, heap->array[p]);
145
0
       i = p, p = heap_parent(i))
146
0
  {
147
0
    heap->array[i] = heap->array[p];
148
0
    if (heap->index != NULL) {
149
0
      (heap->index)(heap->array[i], i);
150
0
    }
151
0
  }
152
0
  heap->array[i] = elt;
153
0
  if (heap->index != NULL) {
154
0
    (heap->index)(heap->array[i], i);
155
0
  }
156
157
0
  INSIST(HEAPCONDITION(i));
158
0
  heap_check(heap);
159
0
}
160
161
static void
162
0
sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
163
0
  unsigned int j, size, half_size;
164
0
  size = heap->last;
165
0
  half_size = size / 2;
166
0
  while (i <= half_size) {
167
    /* Find the smallest of the (at most) two children. */
168
0
    j = heap_left(i);
169
0
    if (j < size &&
170
0
        heap->compare(heap->array[j + 1], heap->array[j]))
171
0
    {
172
0
      j++;
173
0
    }
174
0
    if (heap->compare(elt, heap->array[j])) {
175
0
      break;
176
0
    }
177
0
    heap->array[i] = heap->array[j];
178
0
    if (heap->index != NULL) {
179
0
      (heap->index)(heap->array[i], i);
180
0
    }
181
0
    i = j;
182
0
  }
183
0
  heap->array[i] = elt;
184
0
  if (heap->index != NULL) {
185
0
    (heap->index)(heap->array[i], i);
186
0
  }
187
188
0
  INSIST(HEAPCONDITION(i));
189
0
  heap_check(heap);
190
0
}
191
192
void
193
0
isc_heap_insert(isc_heap_t *heap, void *elt) {
194
0
  unsigned int new_last;
195
196
0
  REQUIRE(VALID_HEAP(heap));
197
198
0
  heap_check(heap);
199
0
  new_last = heap->last + 1;
200
0
  RUNTIME_CHECK(new_last > 0); /* overflow check */
201
0
  if (new_last >= heap->size) {
202
0
    resize(heap);
203
0
  }
204
0
  heap->last = new_last;
205
206
0
  float_up(heap, new_last, elt);
207
0
}
208
209
void
210
0
isc_heap_delete(isc_heap_t *heap, unsigned int idx) {
211
0
  void *elt;
212
0
  bool less;
213
214
0
  REQUIRE(VALID_HEAP(heap));
215
0
  REQUIRE(idx >= 1 && idx <= heap->last);
216
217
0
  heap_check(heap);
218
0
  if (heap->index != NULL) {
219
0
    (heap->index)(heap->array[idx], 0);
220
0
  }
221
0
  if (idx == heap->last) {
222
0
    heap->array[heap->last] = NULL;
223
0
    heap->last--;
224
0
    heap_check(heap);
225
0
  } else {
226
0
    elt = heap->array[heap->last];
227
0
    heap->array[heap->last] = NULL;
228
0
    heap->last--;
229
230
0
    less = heap->compare(elt, heap->array[idx]);
231
0
    heap->array[idx] = elt;
232
0
    if (less) {
233
0
      float_up(heap, idx, heap->array[idx]);
234
0
    } else {
235
0
      sink_down(heap, idx, heap->array[idx]);
236
0
    }
237
0
  }
238
0
}
239
240
void
241
0
isc_heap_increased(isc_heap_t *heap, unsigned int idx) {
242
0
  REQUIRE(VALID_HEAP(heap));
243
0
  REQUIRE(idx >= 1 && idx <= heap->last);
244
245
0
  float_up(heap, idx, heap->array[idx]);
246
0
}
247
248
void
249
0
isc_heap_decreased(isc_heap_t *heap, unsigned int idx) {
250
0
  REQUIRE(VALID_HEAP(heap));
251
0
  REQUIRE(idx >= 1 && idx <= heap->last);
252
253
0
  sink_down(heap, idx, heap->array[idx]);
254
0
}
255
256
void *
257
0
isc_heap_element(isc_heap_t *heap, unsigned int idx) {
258
0
  REQUIRE(VALID_HEAP(heap));
259
0
  REQUIRE(idx >= 1);
260
261
0
  heap_check(heap);
262
0
  if (idx <= heap->last) {
263
0
    return heap->array[idx];
264
0
  }
265
0
  return NULL;
266
0
}
267
268
void
269
0
isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) {
270
0
  unsigned int i;
271
272
0
  REQUIRE(VALID_HEAP(heap));
273
0
  REQUIRE(action != NULL);
274
275
0
  for (i = 1; i <= heap->last; i++) {
276
0
    (action)(heap->array[i], uap);
277
0
  }
278
0
}