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