1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2012 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "nghttp2_pq.h"
26 
27 #include <stdio.h>
28 #include <assert.h>
29 
30 #include "nghttp2_helper.h"
31 
nghttp2_pq_init(nghttp2_pq * pq,nghttp2_less less,nghttp2_mem * mem)32 int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem)
33 {
34     pq->mem = mem;
35     pq->capacity = 0;
36     pq->q = NULL;
37     pq->length = 0;
38     pq->less = less;
39     return 0;
40 }
41 
nghttp2_pq_free(nghttp2_pq * pq)42 void nghttp2_pq_free(nghttp2_pq *pq)
43 {
44     nghttp2_mem_free(pq->mem, pq->q);
45     pq->q = NULL;
46 }
47 
swap(nghttp2_pq * pq,size_t i,size_t j)48 static void swap(nghttp2_pq *pq, size_t i, size_t j)
49 {
50     nghttp2_pq_entry *a = pq->q[i];
51     nghttp2_pq_entry *b = pq->q[j];
52 
53     pq->q[i] = b;
54     b->index = i;
55     pq->q[j] = a;
56     a->index = j;
57 }
58 
bubble_up(nghttp2_pq * pq,size_t index)59 static void bubble_up(nghttp2_pq *pq, size_t index)
60 {
61     size_t parent;
62     while (index != 0) {
63         parent = (index - 1) / 2;
64         if (!pq->less(pq->q[index], pq->q[parent])) {
65             return;
66         }
67         swap(pq, parent, index);
68         index = parent;
69     }
70 }
71 
nghttp2_pq_push(nghttp2_pq * pq,nghttp2_pq_entry * item)72 int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item)
73 {
74     if (pq->capacity <= pq->length) {
75         void *nq;
76         size_t ncapacity;
77 
78         ncapacity = nghttp2_max(4, (pq->capacity * 2));
79 
80         nq = nghttp2_mem_realloc(pq->mem, pq->q,
81                                  ncapacity * sizeof(nghttp2_pq_entry *));
82         if (nq == NULL) {
83             return NGHTTP2_ERR_NOMEM;
84         }
85         pq->capacity = ncapacity;
86         pq->q = nq;
87     }
88     pq->q[pq->length] = item;
89     item->index = pq->length;
90     ++pq->length;
91     bubble_up(pq, pq->length - 1);
92     return 0;
93 }
94 
nghttp2_pq_top(nghttp2_pq * pq)95 nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq)
96 {
97     if (pq->length == 0) {
98         return NULL;
99     } else {
100         return pq->q[0];
101     }
102 }
103 
bubble_down(nghttp2_pq * pq,size_t index)104 static void bubble_down(nghttp2_pq *pq, size_t index)
105 {
106     size_t i, j, minindex;
107     for (;;) {
108         j = index * 2 + 1;
109         minindex = index;
110         for (i = 0; i < 2; ++i, ++j) {
111             if (j >= pq->length) {
112                 break;
113             }
114             if (pq->less(pq->q[j], pq->q[minindex])) {
115                 minindex = j;
116             }
117         }
118         if (minindex == index) {
119             return;
120         }
121         swap(pq, index, minindex);
122         index = minindex;
123     }
124 }
125 
nghttp2_pq_pop(nghttp2_pq * pq)126 void nghttp2_pq_pop(nghttp2_pq *pq)
127 {
128     if (pq->length > 0) {
129         pq->q[0] = pq->q[pq->length - 1];
130         pq->q[0]->index = 0;
131         --pq->length;
132         bubble_down(pq, 0);
133     }
134 }
135 
nghttp2_pq_remove(nghttp2_pq * pq,nghttp2_pq_entry * item)136 void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item)
137 {
138     assert(pq->q[item->index] == item);
139 
140     if (item->index == 0) {
141         nghttp2_pq_pop(pq);
142         return;
143     }
144 
145     if (item->index == pq->length - 1) {
146         --pq->length;
147         return;
148     }
149 
150     pq->q[item->index] = pq->q[pq->length - 1];
151     pq->q[item->index]->index = item->index;
152     --pq->length;
153 
154     if (pq->less(item, pq->q[item->index])) {
155         bubble_down(pq, item->index);
156     } else {
157         bubble_up(pq, item->index);
158     }
159 }
160 
nghttp2_pq_empty(nghttp2_pq * pq)161 int nghttp2_pq_empty(nghttp2_pq *pq)
162 {
163     return pq->length == 0;
164 }
165 
nghttp2_pq_size(nghttp2_pq * pq)166 size_t nghttp2_pq_size(nghttp2_pq *pq)
167 {
168     return pq->length;
169 }
170 
nghttp2_pq_update(nghttp2_pq * pq,nghttp2_pq_item_cb fun,void * arg)171 void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg)
172 {
173     size_t i;
174     int rv = 0;
175     if (pq->length == 0) {
176         return;
177     }
178     for (i = 0; i < pq->length; ++i) {
179         rv |= (*fun)(pq->q[i], arg);
180     }
181     if (rv) {
182         for (i = pq->length; i > 0; --i) {
183             bubble_down(pq, i - 1);
184         }
185     }
186 }
187 
nghttp2_pq_each(nghttp2_pq * pq,nghttp2_pq_item_cb fun,void * arg)188 int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg)
189 {
190     size_t i;
191 
192     if (pq->length == 0) {
193         return 0;
194     }
195     for (i = 0; i < pq->length; ++i) {
196         if ((*fun)(pq->q[i], arg)) {
197             return 1;
198         }
199     }
200     return 0;
201 }
202