xref: /freebsd/crypto/openssl/ssl/priority_queue.c (revision e7be843b4a162e68651d3911f0357ed464915629)
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