1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery *
4*e7be843bSPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e7be843bSPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*e7be843bSPierre Pronchery * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery */
9*e7be843bSPierre Pronchery
10*e7be843bSPierre Pronchery #include <openssl/crypto.h>
11*e7be843bSPierre Pronchery #include <openssl/err.h>
12*e7be843bSPierre Pronchery #include <assert.h>
13*e7be843bSPierre Pronchery #include "internal/priority_queue.h"
14*e7be843bSPierre Pronchery #include "internal/safe_math.h"
15*e7be843bSPierre Pronchery #include "internal/numbers.h"
16*e7be843bSPierre Pronchery
17*e7be843bSPierre Pronchery OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
18*e7be843bSPierre Pronchery
19*e7be843bSPierre Pronchery /*
20*e7be843bSPierre Pronchery * Fundamental operations:
21*e7be843bSPierre Pronchery * Binary Heap Fibonacci Heap
22*e7be843bSPierre Pronchery * Get smallest O(1) O(1)
23*e7be843bSPierre Pronchery * Delete any O(log n) O(log n) average but worst O(n)
24*e7be843bSPierre Pronchery * Insert O(log n) O(1)
25*e7be843bSPierre Pronchery *
26*e7be843bSPierre Pronchery * Not supported:
27*e7be843bSPierre Pronchery * Merge two structures O(log n) O(1)
28*e7be843bSPierre Pronchery * Decrease key O(log n) O(1)
29*e7be843bSPierre Pronchery * Increase key O(log n) ?
30*e7be843bSPierre Pronchery *
31*e7be843bSPierre Pronchery * The Fibonacci heap is quite a bit more complicated to implement and has
32*e7be843bSPierre Pronchery * larger overhead in practice. We favour the binary heap here. A multi-way
33*e7be843bSPierre Pronchery * (ternary or quaternary) heap might elicit a performance advantage via better
34*e7be843bSPierre Pronchery * cache access patterns.
35*e7be843bSPierre Pronchery */
36*e7be843bSPierre Pronchery
37*e7be843bSPierre Pronchery struct pq_heap_st {
38*e7be843bSPierre Pronchery void *data; /* User supplied data pointer */
39*e7be843bSPierre Pronchery size_t index; /* Constant index in elements[] */
40*e7be843bSPierre Pronchery };
41*e7be843bSPierre Pronchery
42*e7be843bSPierre Pronchery struct pq_elem_st {
43*e7be843bSPierre Pronchery size_t posn; /* Current index in heap[] or link in free list */
44*e7be843bSPierre Pronchery #ifndef NDEBUG
45*e7be843bSPierre Pronchery int used; /* Debug flag indicating that this is in use */
46*e7be843bSPierre Pronchery #endif
47*e7be843bSPierre Pronchery };
48*e7be843bSPierre Pronchery
49*e7be843bSPierre Pronchery struct ossl_pqueue_st {
50*e7be843bSPierre Pronchery struct pq_heap_st *heap;
51*e7be843bSPierre Pronchery struct pq_elem_st *elements;
52*e7be843bSPierre Pronchery int (*compare)(const void *, const void *);
53*e7be843bSPierre Pronchery size_t htop; /* Highest used heap element */
54*e7be843bSPierre Pronchery size_t hmax; /* Allocated heap & element space */
55*e7be843bSPierre Pronchery size_t freelist; /* Index into elements[], start of free element list */
56*e7be843bSPierre Pronchery };
57*e7be843bSPierre Pronchery
58*e7be843bSPierre Pronchery /*
59*e7be843bSPierre Pronchery * The initial and maximum number of elements in the heap.
60*e7be843bSPierre Pronchery */
61*e7be843bSPierre Pronchery static const size_t min_nodes = 8;
62*e7be843bSPierre Pronchery static const size_t max_nodes =
63*e7be843bSPierre Pronchery SIZE_MAX / (sizeof(struct pq_heap_st) > sizeof(struct pq_elem_st)
64*e7be843bSPierre Pronchery ? sizeof(struct pq_heap_st) : sizeof(struct pq_elem_st));
65*e7be843bSPierre Pronchery
66*e7be843bSPierre Pronchery #ifndef NDEBUG
67*e7be843bSPierre Pronchery /* Some basic sanity checking of the data structure */
68*e7be843bSPierre Pronchery # define ASSERT_USED(pq, idx) \
69*e7be843bSPierre Pronchery assert(pq->elements[pq->heap[idx].index].used); \
70*e7be843bSPierre Pronchery assert(pq->elements[pq->heap[idx].index].posn == idx)
71*e7be843bSPierre Pronchery # define ASSERT_ELEM_USED(pq, elem) \
72*e7be843bSPierre Pronchery assert(pq->elements[elem].used)
73*e7be843bSPierre Pronchery #else
74*e7be843bSPierre Pronchery # define ASSERT_USED(pq, idx)
75*e7be843bSPierre Pronchery # define ASSERT_ELEM_USED(pq, elem)
76*e7be843bSPierre Pronchery #endif
77*e7be843bSPierre Pronchery
78*e7be843bSPierre Pronchery /*
79*e7be843bSPierre Pronchery * Calculate the array growth based on the target size.
80*e7be843bSPierre Pronchery *
81*e7be843bSPierre Pronchery * The growth factor is a rational number and is defined by a numerator
82*e7be843bSPierre Pronchery * and a denominator. According to Andrew Koenig in his paper "Why Are
83*e7be843bSPierre Pronchery * Vectors Efficient?" from JOOP 11(5) 1998, this factor should be less
84*e7be843bSPierre Pronchery * than the golden ratio (1.618...).
85*e7be843bSPierre Pronchery *
86*e7be843bSPierre Pronchery * We use an expansion factor of 8 / 5 = 1.6
87*e7be843bSPierre Pronchery */
compute_pqueue_growth(size_t target,size_t current)88*e7be843bSPierre Pronchery static ossl_inline size_t compute_pqueue_growth(size_t target, size_t current)
89*e7be843bSPierre Pronchery {
90*e7be843bSPierre Pronchery int err = 0;
91*e7be843bSPierre Pronchery
92*e7be843bSPierre Pronchery while (current < target) {
93*e7be843bSPierre Pronchery if (current >= max_nodes)
94*e7be843bSPierre Pronchery return 0;
95*e7be843bSPierre Pronchery
96*e7be843bSPierre Pronchery current = safe_muldiv_size_t(current, 8, 5, &err);
97*e7be843bSPierre Pronchery if (err)
98*e7be843bSPierre Pronchery return 0;
99*e7be843bSPierre Pronchery if (current >= max_nodes)
100*e7be843bSPierre Pronchery current = max_nodes;
101*e7be843bSPierre Pronchery }
102*e7be843bSPierre Pronchery return current;
103*e7be843bSPierre Pronchery }
104*e7be843bSPierre Pronchery
pqueue_swap_elem(OSSL_PQUEUE * pq,size_t i,size_t j)105*e7be843bSPierre Pronchery static ossl_inline void pqueue_swap_elem(OSSL_PQUEUE *pq, size_t i, size_t j)
106*e7be843bSPierre Pronchery {
107*e7be843bSPierre Pronchery struct pq_heap_st *h = pq->heap, t_h;
108*e7be843bSPierre Pronchery struct pq_elem_st *e = pq->elements;
109*e7be843bSPierre Pronchery
110*e7be843bSPierre Pronchery ASSERT_USED(pq, i);
111*e7be843bSPierre Pronchery ASSERT_USED(pq, j);
112*e7be843bSPierre Pronchery
113*e7be843bSPierre Pronchery t_h = h[i];
114*e7be843bSPierre Pronchery h[i] = h[j];
115*e7be843bSPierre Pronchery h[j] = t_h;
116*e7be843bSPierre Pronchery
117*e7be843bSPierre Pronchery e[h[i].index].posn = i;
118*e7be843bSPierre Pronchery e[h[j].index].posn = j;
119*e7be843bSPierre Pronchery }
120*e7be843bSPierre Pronchery
pqueue_move_elem(OSSL_PQUEUE * pq,size_t from,size_t to)121*e7be843bSPierre Pronchery static ossl_inline void pqueue_move_elem(OSSL_PQUEUE *pq, size_t from, size_t to)
122*e7be843bSPierre Pronchery {
123*e7be843bSPierre Pronchery struct pq_heap_st *h = pq->heap;
124*e7be843bSPierre Pronchery struct pq_elem_st *e = pq->elements;
125*e7be843bSPierre Pronchery
126*e7be843bSPierre Pronchery ASSERT_USED(pq, from);
127*e7be843bSPierre Pronchery
128*e7be843bSPierre Pronchery h[to] = h[from];
129*e7be843bSPierre Pronchery e[h[to].index].posn = to;
130*e7be843bSPierre Pronchery }
131*e7be843bSPierre Pronchery
132*e7be843bSPierre Pronchery /*
133*e7be843bSPierre Pronchery * Force the specified element to the front of the heap. This breaks
134*e7be843bSPierre Pronchery * the heap partial ordering pre-condition.
135*e7be843bSPierre Pronchery */
pqueue_force_bottom(OSSL_PQUEUE * pq,size_t n)136*e7be843bSPierre Pronchery static ossl_inline void pqueue_force_bottom(OSSL_PQUEUE *pq, size_t n)
137*e7be843bSPierre Pronchery {
138*e7be843bSPierre Pronchery ASSERT_USED(pq, n);
139*e7be843bSPierre Pronchery while (n > 0) {
140*e7be843bSPierre Pronchery const size_t p = (n - 1) / 2;
141*e7be843bSPierre Pronchery
142*e7be843bSPierre Pronchery ASSERT_USED(pq, p);
143*e7be843bSPierre Pronchery pqueue_swap_elem(pq, n, p);
144*e7be843bSPierre Pronchery n = p;
145*e7be843bSPierre Pronchery }
146*e7be843bSPierre Pronchery }
147*e7be843bSPierre Pronchery
148*e7be843bSPierre Pronchery /*
149*e7be843bSPierre Pronchery * Move an element down to its correct position to restore the partial
150*e7be843bSPierre Pronchery * order pre-condition.
151*e7be843bSPierre Pronchery */
pqueue_move_down(OSSL_PQUEUE * pq,size_t n)152*e7be843bSPierre Pronchery static ossl_inline void pqueue_move_down(OSSL_PQUEUE *pq, size_t n)
153*e7be843bSPierre Pronchery {
154*e7be843bSPierre Pronchery struct pq_heap_st *h = pq->heap;
155*e7be843bSPierre Pronchery
156*e7be843bSPierre Pronchery ASSERT_USED(pq, n);
157*e7be843bSPierre Pronchery while (n > 0) {
158*e7be843bSPierre Pronchery const size_t p = (n - 1) / 2;
159*e7be843bSPierre Pronchery
160*e7be843bSPierre Pronchery ASSERT_USED(pq, p);
161*e7be843bSPierre Pronchery if (pq->compare(h[n].data, h[p].data) >= 0)
162*e7be843bSPierre Pronchery break;
163*e7be843bSPierre Pronchery pqueue_swap_elem(pq, n, p);
164*e7be843bSPierre Pronchery n = p;
165*e7be843bSPierre Pronchery }
166*e7be843bSPierre Pronchery }
167*e7be843bSPierre Pronchery
168*e7be843bSPierre Pronchery /*
169*e7be843bSPierre Pronchery * Move an element up to its correct position to restore the partial
170*e7be843bSPierre Pronchery * order pre-condition.
171*e7be843bSPierre Pronchery */
pqueue_move_up(OSSL_PQUEUE * pq,size_t n)172*e7be843bSPierre Pronchery static ossl_inline void pqueue_move_up(OSSL_PQUEUE *pq, size_t n)
173*e7be843bSPierre Pronchery {
174*e7be843bSPierre Pronchery struct pq_heap_st *h = pq->heap;
175*e7be843bSPierre Pronchery size_t p = n * 2 + 1;
176*e7be843bSPierre Pronchery
177*e7be843bSPierre Pronchery ASSERT_USED(pq, n);
178*e7be843bSPierre Pronchery if (pq->htop > p + 1) {
179*e7be843bSPierre Pronchery ASSERT_USED(pq, p);
180*e7be843bSPierre Pronchery ASSERT_USED(pq, p + 1);
181*e7be843bSPierre Pronchery if (pq->compare(h[p].data, h[p + 1].data) > 0)
182*e7be843bSPierre Pronchery p++;
183*e7be843bSPierre Pronchery }
184*e7be843bSPierre Pronchery while (pq->htop > p && pq->compare(h[p].data, h[n].data) < 0) {
185*e7be843bSPierre Pronchery ASSERT_USED(pq, p);
186*e7be843bSPierre Pronchery pqueue_swap_elem(pq, n, p);
187*e7be843bSPierre Pronchery n = p;
188*e7be843bSPierre Pronchery p = n * 2 + 1;
189*e7be843bSPierre Pronchery if (pq->htop > p + 1) {
190*e7be843bSPierre Pronchery ASSERT_USED(pq, p + 1);
191*e7be843bSPierre Pronchery if (pq->compare(h[p].data, h[p + 1].data) > 0)
192*e7be843bSPierre Pronchery p++;
193*e7be843bSPierre Pronchery }
194*e7be843bSPierre Pronchery }
195*e7be843bSPierre Pronchery }
196*e7be843bSPierre Pronchery
ossl_pqueue_push(OSSL_PQUEUE * pq,void * data,size_t * elem)197*e7be843bSPierre Pronchery int ossl_pqueue_push(OSSL_PQUEUE *pq, void *data, size_t *elem)
198*e7be843bSPierre Pronchery {
199*e7be843bSPierre Pronchery size_t n, m;
200*e7be843bSPierre Pronchery
201*e7be843bSPierre Pronchery if (!ossl_pqueue_reserve(pq, 1))
202*e7be843bSPierre Pronchery return 0;
203*e7be843bSPierre Pronchery
204*e7be843bSPierre Pronchery n = pq->htop++;
205*e7be843bSPierre Pronchery m = pq->freelist;
206*e7be843bSPierre Pronchery pq->freelist = pq->elements[m].posn;
207*e7be843bSPierre Pronchery
208*e7be843bSPierre Pronchery pq->heap[n].data = data;
209*e7be843bSPierre Pronchery pq->heap[n].index = m;
210*e7be843bSPierre Pronchery
211*e7be843bSPierre Pronchery pq->elements[m].posn = n;
212*e7be843bSPierre Pronchery #ifndef NDEBUG
213*e7be843bSPierre Pronchery pq->elements[m].used = 1;
214*e7be843bSPierre Pronchery #endif
215*e7be843bSPierre Pronchery pqueue_move_down(pq, n);
216*e7be843bSPierre Pronchery if (elem != NULL)
217*e7be843bSPierre Pronchery *elem = m;
218*e7be843bSPierre Pronchery return 1;
219*e7be843bSPierre Pronchery }
220*e7be843bSPierre Pronchery
ossl_pqueue_peek(const OSSL_PQUEUE * pq)221*e7be843bSPierre Pronchery void *ossl_pqueue_peek(const OSSL_PQUEUE *pq)
222*e7be843bSPierre Pronchery {
223*e7be843bSPierre Pronchery if (pq->htop > 0) {
224*e7be843bSPierre Pronchery ASSERT_USED(pq, 0);
225*e7be843bSPierre Pronchery return pq->heap->data;
226*e7be843bSPierre Pronchery }
227*e7be843bSPierre Pronchery return NULL;
228*e7be843bSPierre Pronchery }
229*e7be843bSPierre Pronchery
ossl_pqueue_pop(OSSL_PQUEUE * pq)230*e7be843bSPierre Pronchery void *ossl_pqueue_pop(OSSL_PQUEUE *pq)
231*e7be843bSPierre Pronchery {
232*e7be843bSPierre Pronchery void *res;
233*e7be843bSPierre Pronchery size_t elem;
234*e7be843bSPierre Pronchery
235*e7be843bSPierre Pronchery if (pq == NULL || pq->htop == 0)
236*e7be843bSPierre Pronchery return NULL;
237*e7be843bSPierre Pronchery
238*e7be843bSPierre Pronchery ASSERT_USED(pq, 0);
239*e7be843bSPierre Pronchery res = pq->heap->data;
240*e7be843bSPierre Pronchery elem = pq->heap->index;
241*e7be843bSPierre Pronchery
242*e7be843bSPierre Pronchery if (--pq->htop != 0) {
243*e7be843bSPierre Pronchery pqueue_move_elem(pq, pq->htop, 0);
244*e7be843bSPierre Pronchery pqueue_move_up(pq, 0);
245*e7be843bSPierre Pronchery }
246*e7be843bSPierre Pronchery
247*e7be843bSPierre Pronchery pq->elements[elem].posn = pq->freelist;
248*e7be843bSPierre Pronchery pq->freelist = elem;
249*e7be843bSPierre Pronchery #ifndef NDEBUG
250*e7be843bSPierre Pronchery pq->elements[elem].used = 0;
251*e7be843bSPierre Pronchery #endif
252*e7be843bSPierre Pronchery return res;
253*e7be843bSPierre Pronchery }
254*e7be843bSPierre Pronchery
ossl_pqueue_remove(OSSL_PQUEUE * pq,size_t elem)255*e7be843bSPierre Pronchery void *ossl_pqueue_remove(OSSL_PQUEUE *pq, size_t elem)
256*e7be843bSPierre Pronchery {
257*e7be843bSPierre Pronchery size_t n;
258*e7be843bSPierre Pronchery
259*e7be843bSPierre Pronchery if (pq == NULL || elem >= pq->hmax || pq->htop == 0)
260*e7be843bSPierre Pronchery return 0;
261*e7be843bSPierre Pronchery
262*e7be843bSPierre Pronchery ASSERT_ELEM_USED(pq, elem);
263*e7be843bSPierre Pronchery n = pq->elements[elem].posn;
264*e7be843bSPierre Pronchery
265*e7be843bSPierre Pronchery ASSERT_USED(pq, n);
266*e7be843bSPierre Pronchery
267*e7be843bSPierre Pronchery if (n == pq->htop - 1) {
268*e7be843bSPierre Pronchery pq->elements[elem].posn = pq->freelist;
269*e7be843bSPierre Pronchery pq->freelist = elem;
270*e7be843bSPierre Pronchery #ifndef NDEBUG
271*e7be843bSPierre Pronchery pq->elements[elem].used = 0;
272*e7be843bSPierre Pronchery #endif
273*e7be843bSPierre Pronchery return pq->heap[--pq->htop].data;
274*e7be843bSPierre Pronchery }
275*e7be843bSPierre Pronchery if (n > 0)
276*e7be843bSPierre Pronchery pqueue_force_bottom(pq, n);
277*e7be843bSPierre Pronchery return ossl_pqueue_pop(pq);
278*e7be843bSPierre Pronchery }
279*e7be843bSPierre Pronchery
pqueue_add_freelist(OSSL_PQUEUE * pq,size_t from)280*e7be843bSPierre Pronchery static void pqueue_add_freelist(OSSL_PQUEUE *pq, size_t from)
281*e7be843bSPierre Pronchery {
282*e7be843bSPierre Pronchery struct pq_elem_st *e = pq->elements;
283*e7be843bSPierre Pronchery size_t i;
284*e7be843bSPierre Pronchery
285*e7be843bSPierre Pronchery #ifndef NDEBUG
286*e7be843bSPierre Pronchery for (i = from; i < pq->hmax; i++)
287*e7be843bSPierre Pronchery e[i].used = 0;
288*e7be843bSPierre Pronchery #endif
289*e7be843bSPierre Pronchery e[from].posn = pq->freelist;
290*e7be843bSPierre Pronchery for (i = from + 1; i < pq->hmax; i++)
291*e7be843bSPierre Pronchery e[i].posn = i - 1;
292*e7be843bSPierre Pronchery pq->freelist = pq->hmax - 1;
293*e7be843bSPierre Pronchery }
294*e7be843bSPierre Pronchery
ossl_pqueue_reserve(OSSL_PQUEUE * pq,size_t n)295*e7be843bSPierre Pronchery int ossl_pqueue_reserve(OSSL_PQUEUE *pq, size_t n)
296*e7be843bSPierre Pronchery {
297*e7be843bSPierre Pronchery size_t new_max, cur_max;
298*e7be843bSPierre Pronchery struct pq_heap_st *h;
299*e7be843bSPierre Pronchery struct pq_elem_st *e;
300*e7be843bSPierre Pronchery
301*e7be843bSPierre Pronchery if (pq == NULL)
302*e7be843bSPierre Pronchery return 0;
303*e7be843bSPierre Pronchery cur_max = pq->hmax;
304*e7be843bSPierre Pronchery if (pq->htop + n < cur_max)
305*e7be843bSPierre Pronchery return 1;
306*e7be843bSPierre Pronchery
307*e7be843bSPierre Pronchery new_max = compute_pqueue_growth(n + cur_max, cur_max);
308*e7be843bSPierre Pronchery if (new_max == 0) {
309*e7be843bSPierre Pronchery ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
310*e7be843bSPierre Pronchery return 0;
311*e7be843bSPierre Pronchery }
312*e7be843bSPierre Pronchery
313*e7be843bSPierre Pronchery h = OPENSSL_realloc(pq->heap, new_max * sizeof(*pq->heap));
314*e7be843bSPierre Pronchery if (h == NULL)
315*e7be843bSPierre Pronchery return 0;
316*e7be843bSPierre Pronchery pq->heap = h;
317*e7be843bSPierre Pronchery
318*e7be843bSPierre Pronchery e = OPENSSL_realloc(pq->elements, new_max * sizeof(*pq->elements));
319*e7be843bSPierre Pronchery if (e == NULL)
320*e7be843bSPierre Pronchery return 0;
321*e7be843bSPierre Pronchery pq->elements = e;
322*e7be843bSPierre Pronchery
323*e7be843bSPierre Pronchery pq->hmax = new_max;
324*e7be843bSPierre Pronchery pqueue_add_freelist(pq, cur_max);
325*e7be843bSPierre Pronchery return 1;
326*e7be843bSPierre Pronchery }
327*e7be843bSPierre Pronchery
ossl_pqueue_new(int (* compare)(const void *,const void *))328*e7be843bSPierre Pronchery OSSL_PQUEUE *ossl_pqueue_new(int (*compare)(const void *, const void *))
329*e7be843bSPierre Pronchery {
330*e7be843bSPierre Pronchery OSSL_PQUEUE *pq;
331*e7be843bSPierre Pronchery
332*e7be843bSPierre Pronchery if (compare == NULL)
333*e7be843bSPierre Pronchery return NULL;
334*e7be843bSPierre Pronchery
335*e7be843bSPierre Pronchery pq = OPENSSL_malloc(sizeof(*pq));
336*e7be843bSPierre Pronchery if (pq == NULL)
337*e7be843bSPierre Pronchery return NULL;
338*e7be843bSPierre Pronchery pq->compare = compare;
339*e7be843bSPierre Pronchery pq->hmax = min_nodes;
340*e7be843bSPierre Pronchery pq->htop = 0;
341*e7be843bSPierre Pronchery pq->freelist = 0;
342*e7be843bSPierre Pronchery pq->heap = OPENSSL_malloc(sizeof(*pq->heap) * min_nodes);
343*e7be843bSPierre Pronchery pq->elements = OPENSSL_malloc(sizeof(*pq->elements) * min_nodes);
344*e7be843bSPierre Pronchery if (pq->heap == NULL || pq->elements == NULL) {
345*e7be843bSPierre Pronchery ossl_pqueue_free(pq);
346*e7be843bSPierre Pronchery return NULL;
347*e7be843bSPierre Pronchery }
348*e7be843bSPierre Pronchery pqueue_add_freelist(pq, 0);
349*e7be843bSPierre Pronchery return pq;
350*e7be843bSPierre Pronchery }
351*e7be843bSPierre Pronchery
ossl_pqueue_free(OSSL_PQUEUE * pq)352*e7be843bSPierre Pronchery void ossl_pqueue_free(OSSL_PQUEUE *pq)
353*e7be843bSPierre Pronchery {
354*e7be843bSPierre Pronchery if (pq != NULL) {
355*e7be843bSPierre Pronchery OPENSSL_free(pq->heap);
356*e7be843bSPierre Pronchery OPENSSL_free(pq->elements);
357*e7be843bSPierre Pronchery OPENSSL_free(pq);
358*e7be843bSPierre Pronchery }
359*e7be843bSPierre Pronchery }
360*e7be843bSPierre Pronchery
ossl_pqueue_pop_free(OSSL_PQUEUE * pq,void (* freefunc)(void *))361*e7be843bSPierre Pronchery void ossl_pqueue_pop_free(OSSL_PQUEUE *pq, void (*freefunc)(void *))
362*e7be843bSPierre Pronchery {
363*e7be843bSPierre Pronchery size_t i;
364*e7be843bSPierre Pronchery
365*e7be843bSPierre Pronchery if (pq != NULL) {
366*e7be843bSPierre Pronchery for (i = 0; i < pq->htop; i++)
367*e7be843bSPierre Pronchery (*freefunc)(pq->heap[i].data);
368*e7be843bSPierre Pronchery ossl_pqueue_free(pq);
369*e7be843bSPierre Pronchery }
370*e7be843bSPierre Pronchery }
371*e7be843bSPierre Pronchery
ossl_pqueue_num(const OSSL_PQUEUE * pq)372*e7be843bSPierre Pronchery size_t ossl_pqueue_num(const OSSL_PQUEUE *pq)
373*e7be843bSPierre Pronchery {
374*e7be843bSPierre Pronchery return pq != NULL ? pq->htop : 0;
375*e7be843bSPierre Pronchery }
376