1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2020 nghttp2 contributors
5 * Copyright (c) 2018 ngtcp2 contributors
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26 #include "nghttp2_ksl.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <stdio.h>
32
33 #include "nghttp2_mem.h"
34
ksl_nodelen(size_t keylen)35 static size_t ksl_nodelen(size_t keylen) {
36 return (sizeof(nghttp2_ksl_node) + keylen - sizeof(uint64_t) + 0xf) &
37 (size_t)~0xf;
38 }
39
ksl_blklen(size_t nodelen)40 static size_t ksl_blklen(size_t nodelen) {
41 return sizeof(nghttp2_ksl_blk) + nodelen * NGHTTP2_KSL_MAX_NBLK -
42 sizeof(uint64_t);
43 }
44
45 /*
46 * ksl_node_set_key sets |key| to |node|.
47 */
ksl_node_set_key(nghttp2_ksl * ksl,nghttp2_ksl_node * node,const void * key)48 static void ksl_node_set_key(nghttp2_ksl *ksl, nghttp2_ksl_node *node,
49 const void *key) {
50 memcpy(node->key, key, ksl->keylen);
51 }
52
nghttp2_ksl_init(nghttp2_ksl * ksl,nghttp2_ksl_compar compar,size_t keylen,nghttp2_mem * mem)53 int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
54 nghttp2_mem *mem) {
55 size_t nodelen = ksl_nodelen(keylen);
56 size_t blklen = ksl_blklen(nodelen);
57 nghttp2_ksl_blk *head;
58
59 ksl->head = nghttp2_mem_malloc(mem, blklen);
60 if (!ksl->head) {
61 return NGHTTP2_ERR_NOMEM;
62 }
63 ksl->front = ksl->back = ksl->head;
64 ksl->compar = compar;
65 ksl->keylen = keylen;
66 ksl->nodelen = nodelen;
67 ksl->n = 0;
68 ksl->mem = mem;
69
70 head = ksl->head;
71 head->next = head->prev = NULL;
72 head->n = 0;
73 head->leaf = 1;
74
75 return 0;
76 }
77
78 /*
79 * ksl_free_blk frees |blk| recursively.
80 */
ksl_free_blk(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk)81 static void ksl_free_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
82 size_t i;
83
84 if (!blk->leaf) {
85 for (i = 0; i < blk->n; ++i) {
86 ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk);
87 }
88 }
89
90 nghttp2_mem_free(ksl->mem, blk);
91 }
92
nghttp2_ksl_free(nghttp2_ksl * ksl)93 void nghttp2_ksl_free(nghttp2_ksl *ksl) {
94 if (!ksl) {
95 return;
96 }
97
98 ksl_free_blk(ksl, ksl->head);
99 }
100
101 /*
102 * ksl_split_blk splits |blk| into 2 nghttp2_ksl_blk objects. The new
103 * nghttp2_ksl_blk is always the "right" block.
104 *
105 * It returns the pointer to the nghttp2_ksl_blk created which is the
106 * located at the right of |blk|, or NULL which indicates out of
107 * memory error.
108 */
ksl_split_blk(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk)109 static nghttp2_ksl_blk *ksl_split_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
110 nghttp2_ksl_blk *rblk;
111
112 rblk = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
113 if (rblk == NULL) {
114 return NULL;
115 }
116
117 rblk->next = blk->next;
118 blk->next = rblk;
119 if (rblk->next) {
120 rblk->next->prev = rblk;
121 } else if (ksl->back == blk) {
122 ksl->back = rblk;
123 }
124 rblk->prev = blk;
125 rblk->leaf = blk->leaf;
126
127 rblk->n = blk->n / 2;
128
129 memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
130 ksl->nodelen * rblk->n);
131
132 blk->n -= rblk->n;
133
134 assert(blk->n >= NGHTTP2_KSL_MIN_NBLK);
135 assert(rblk->n >= NGHTTP2_KSL_MIN_NBLK);
136
137 return rblk;
138 }
139
140 /*
141 * ksl_split_node splits a node included in |blk| at the position |i|
142 * into 2 adjacent nodes. The new node is always inserted at the
143 * position |i+1|.
144 *
145 * It returns 0 if it succeeds, or one of the following negative error
146 * codes:
147 *
148 * NGHTTP2_ERR_NOMEM
149 * Out of memory.
150 */
ksl_split_node(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)151 static int ksl_split_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
152 nghttp2_ksl_node *node;
153 nghttp2_ksl_blk *lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
154
155 rblk = ksl_split_blk(ksl, lblk);
156 if (rblk == NULL) {
157 return NGHTTP2_ERR_NOMEM;
158 }
159
160 memmove(blk->nodes + (i + 2) * ksl->nodelen,
161 blk->nodes + (i + 1) * ksl->nodelen,
162 ksl->nodelen * (blk->n - (i + 1)));
163
164 node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
165 node->blk = rblk;
166 ++blk->n;
167 ksl_node_set_key(ksl, node,
168 nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
169
170 node = nghttp2_ksl_nth_node(ksl, blk, i);
171 ksl_node_set_key(ksl, node,
172 nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
173
174 return 0;
175 }
176
177 /*
178 * ksl_split_head splits a head (root) block. It increases the height
179 * of skip list by 1.
180 *
181 * It returns 0 if it succeeds, or one of the following negative error
182 * codes:
183 *
184 * NGHTTP2_ERR_NOMEM
185 * Out of memory.
186 */
ksl_split_head(nghttp2_ksl * ksl)187 static int ksl_split_head(nghttp2_ksl *ksl) {
188 nghttp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
189 nghttp2_ksl_node *node;
190
191 rblk = ksl_split_blk(ksl, ksl->head);
192 if (rblk == NULL) {
193 return NGHTTP2_ERR_NOMEM;
194 }
195
196 lblk = ksl->head;
197
198 nhead = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
199 if (nhead == NULL) {
200 nghttp2_mem_free(ksl->mem, rblk);
201 return NGHTTP2_ERR_NOMEM;
202 }
203 nhead->next = nhead->prev = NULL;
204 nhead->n = 2;
205 nhead->leaf = 0;
206
207 node = nghttp2_ksl_nth_node(ksl, nhead, 0);
208 ksl_node_set_key(ksl, node,
209 nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
210 node->blk = lblk;
211
212 node = nghttp2_ksl_nth_node(ksl, nhead, 1);
213 ksl_node_set_key(ksl, node,
214 nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
215 node->blk = rblk;
216
217 ksl->head = nhead;
218
219 return 0;
220 }
221
222 /*
223 * insert_node inserts a node whose key is |key| with the associated
224 * |data| at the index of |i|. This function assumes that the number
225 * of nodes contained by |blk| is strictly less than
226 * NGHTTP2_KSL_MAX_NBLK.
227 */
ksl_insert_node(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i,const nghttp2_ksl_key * key,void * data)228 static void ksl_insert_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i,
229 const nghttp2_ksl_key *key, void *data) {
230 nghttp2_ksl_node *node;
231
232 assert(blk->n < NGHTTP2_KSL_MAX_NBLK);
233
234 memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
235 ksl->nodelen * (blk->n - i));
236
237 node = nghttp2_ksl_nth_node(ksl, blk, i);
238 ksl_node_set_key(ksl, node, key);
239 node->data = data;
240
241 ++blk->n;
242 }
243
ksl_bsearch(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,const nghttp2_ksl_key * key,nghttp2_ksl_compar compar)244 static size_t ksl_bsearch(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
245 const nghttp2_ksl_key *key,
246 nghttp2_ksl_compar compar) {
247 ssize_t left = -1, right = (ssize_t)blk->n, mid;
248 nghttp2_ksl_node *node;
249
250 while (right - left > 1) {
251 mid = (left + right) / 2;
252 node = nghttp2_ksl_nth_node(ksl, blk, (size_t)mid);
253 if (compar((nghttp2_ksl_key *)node->key, key)) {
254 left = mid;
255 } else {
256 right = mid;
257 }
258 }
259
260 return (size_t)right;
261 }
262
nghttp2_ksl_insert(nghttp2_ksl * ksl,nghttp2_ksl_it * it,const nghttp2_ksl_key * key,void * data)263 int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
264 const nghttp2_ksl_key *key, void *data) {
265 nghttp2_ksl_blk *blk = ksl->head;
266 nghttp2_ksl_node *node;
267 size_t i;
268 int rv;
269
270 if (blk->n == NGHTTP2_KSL_MAX_NBLK) {
271 rv = ksl_split_head(ksl);
272 if (rv != 0) {
273 return rv;
274 }
275 blk = ksl->head;
276 }
277
278 for (;;) {
279 i = ksl_bsearch(ksl, blk, key, ksl->compar);
280
281 if (blk->leaf) {
282 if (i < blk->n &&
283 !ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
284 if (it) {
285 *it = nghttp2_ksl_end(ksl);
286 }
287 return NGHTTP2_ERR_INVALID_ARGUMENT;
288 }
289 ksl_insert_node(ksl, blk, i, key, data);
290 ++ksl->n;
291 if (it) {
292 nghttp2_ksl_it_init(it, ksl, blk, i);
293 }
294 return 0;
295 }
296
297 if (i == blk->n) {
298 /* This insertion extends the largest key in this subtree. */
299 for (; !blk->leaf;) {
300 node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
301 if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
302 rv = ksl_split_node(ksl, blk, blk->n - 1);
303 if (rv != 0) {
304 return rv;
305 }
306 node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
307 }
308 ksl_node_set_key(ksl, node, key);
309 blk = node->blk;
310 }
311 ksl_insert_node(ksl, blk, blk->n, key, data);
312 ++ksl->n;
313 if (it) {
314 nghttp2_ksl_it_init(it, ksl, blk, blk->n - 1);
315 }
316 return 0;
317 }
318
319 node = nghttp2_ksl_nth_node(ksl, blk, i);
320
321 if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
322 rv = ksl_split_node(ksl, blk, i);
323 if (rv != 0) {
324 return rv;
325 }
326 if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
327 node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
328 if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
329 ksl_node_set_key(ksl, node, key);
330 }
331 }
332 }
333
334 blk = node->blk;
335 }
336 }
337
338 /*
339 * ksl_remove_node removes the node included in |blk| at the index of
340 * |i|.
341 */
ksl_remove_node(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)342 static void ksl_remove_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
343 memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
344 ksl->nodelen * (blk->n - (i + 1)));
345
346 --blk->n;
347 }
348
349 /*
350 * ksl_merge_node merges 2 nodes which are the nodes at the index of
351 * |i| and |i + 1|.
352 *
353 * If |blk| is the direct descendant of head (root) block and the head
354 * block contains just 2 nodes, the merged block becomes head block,
355 * which decreases the height of |ksl| by 1.
356 *
357 * This function returns the pointer to the merged block.
358 */
ksl_merge_node(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)359 static nghttp2_ksl_blk *ksl_merge_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
360 size_t i) {
361 nghttp2_ksl_blk *lblk, *rblk;
362
363 assert(i + 1 < blk->n);
364
365 lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
366 rblk = nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk;
367
368 assert(lblk->n + rblk->n < NGHTTP2_KSL_MAX_NBLK);
369
370 memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
371 ksl->nodelen * rblk->n);
372
373 lblk->n += rblk->n;
374 lblk->next = rblk->next;
375 if (lblk->next) {
376 lblk->next->prev = lblk;
377 } else if (ksl->back == rblk) {
378 ksl->back = lblk;
379 }
380
381 nghttp2_mem_free(ksl->mem, rblk);
382
383 if (ksl->head == blk && blk->n == 2) {
384 nghttp2_mem_free(ksl->mem, ksl->head);
385 ksl->head = lblk;
386 } else {
387 ksl_remove_node(ksl, blk, i + 1);
388 ksl_node_set_key(ksl, nghttp2_ksl_nth_node(ksl, blk, i),
389 nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
390 }
391
392 return lblk;
393 }
394
395 /*
396 * ksl_shift_left moves the first node in blk->nodes[i]->blk->nodes to
397 * blk->nodes[i - 1]->blk->nodes.
398 */
ksl_shift_left(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)399 static void ksl_shift_left(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
400 nghttp2_ksl_node *lnode, *rnode, *dest, *src;
401
402 assert(i > 0);
403
404 lnode = nghttp2_ksl_nth_node(ksl, blk, i - 1);
405 rnode = nghttp2_ksl_nth_node(ksl, blk, i);
406
407 assert(lnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
408 assert(rnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
409
410 dest = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n);
411 src = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
412
413 memcpy(dest, src, ksl->nodelen);
414 ksl_node_set_key(ksl, lnode, dest->key);
415 ++lnode->blk->n;
416
417 --rnode->blk->n;
418 memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen,
419 ksl->nodelen * rnode->blk->n);
420 }
421
422 /*
423 * ksl_shift_right moves the last node in blk->nodes[i]->blk->nodes to
424 * blk->nodes[i + 1]->blk->nodes.
425 */
ksl_shift_right(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)426 static void ksl_shift_right(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
427 nghttp2_ksl_node *lnode, *rnode, *dest, *src;
428
429 assert(i < blk->n - 1);
430
431 lnode = nghttp2_ksl_nth_node(ksl, blk, i);
432 rnode = nghttp2_ksl_nth_node(ksl, blk, i + 1);
433
434 assert(lnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
435 assert(rnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
436
437 memmove(rnode->blk->nodes + ksl->nodelen, rnode->blk->nodes,
438 ksl->nodelen * rnode->blk->n);
439 ++rnode->blk->n;
440
441 dest = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
442 src = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1);
443
444 memcpy(dest, src, ksl->nodelen);
445
446 --lnode->blk->n;
447 ksl_node_set_key(
448 ksl, lnode,
449 nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
450 }
451
452 /*
453 * key_equal returns nonzero if |lhs| and |rhs| are equal using the
454 * function |compar|.
455 */
key_equal(nghttp2_ksl_compar compar,const nghttp2_ksl_key * lhs,const nghttp2_ksl_key * rhs)456 static int key_equal(nghttp2_ksl_compar compar, const nghttp2_ksl_key *lhs,
457 const nghttp2_ksl_key *rhs) {
458 return !compar(lhs, rhs) && !compar(rhs, lhs);
459 }
460
nghttp2_ksl_remove(nghttp2_ksl * ksl,nghttp2_ksl_it * it,const nghttp2_ksl_key * key)461 int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
462 const nghttp2_ksl_key *key) {
463 nghttp2_ksl_blk *blk = ksl->head;
464 nghttp2_ksl_node *node;
465 size_t i;
466
467 if (!blk->leaf && blk->n == 2 &&
468 nghttp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP2_KSL_MIN_NBLK &&
469 nghttp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP2_KSL_MIN_NBLK) {
470 blk = ksl_merge_node(ksl, ksl->head, 0);
471 }
472
473 for (;;) {
474 i = ksl_bsearch(ksl, blk, key, ksl->compar);
475
476 if (i == blk->n) {
477 if (it) {
478 *it = nghttp2_ksl_end(ksl);
479 }
480 return NGHTTP2_ERR_INVALID_ARGUMENT;
481 }
482
483 if (blk->leaf) {
484 if (ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
485 if (it) {
486 *it = nghttp2_ksl_end(ksl);
487 }
488 return NGHTTP2_ERR_INVALID_ARGUMENT;
489 }
490 ksl_remove_node(ksl, blk, i);
491 --ksl->n;
492 if (it) {
493 if (blk->n == i && blk->next) {
494 nghttp2_ksl_it_init(it, ksl, blk->next, 0);
495 } else {
496 nghttp2_ksl_it_init(it, ksl, blk, i);
497 }
498 }
499 return 0;
500 }
501
502 node = nghttp2_ksl_nth_node(ksl, blk, i);
503
504 if (node->blk->n == NGHTTP2_KSL_MIN_NBLK) {
505 if (i > 0 && nghttp2_ksl_nth_node(ksl, blk, i - 1)->blk->n >
506 NGHTTP2_KSL_MIN_NBLK) {
507 ksl_shift_right(ksl, blk, i - 1);
508 blk = node->blk;
509 } else if (i + 1 < blk->n &&
510 nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk->n >
511 NGHTTP2_KSL_MIN_NBLK) {
512 ksl_shift_left(ksl, blk, i + 1);
513 blk = node->blk;
514 } else if (i > 0) {
515 blk = ksl_merge_node(ksl, blk, i - 1);
516 } else {
517 assert(i + 1 < blk->n);
518 blk = ksl_merge_node(ksl, blk, i);
519 }
520 } else {
521 blk = node->blk;
522 }
523 }
524 }
525
nghttp2_ksl_lower_bound(nghttp2_ksl * ksl,const nghttp2_ksl_key * key)526 nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
527 const nghttp2_ksl_key *key) {
528 nghttp2_ksl_blk *blk = ksl->head;
529 nghttp2_ksl_it it;
530 size_t i;
531
532 for (;;) {
533 i = ksl_bsearch(ksl, blk, key, ksl->compar);
534
535 if (blk->leaf) {
536 if (i == blk->n && blk->next) {
537 blk = blk->next;
538 i = 0;
539 }
540 nghttp2_ksl_it_init(&it, ksl, blk, i);
541 return it;
542 }
543
544 if (i == blk->n) {
545 /* This happens if descendant has smaller key. Fast forward to
546 find last node in this subtree. */
547 for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
548 ;
549 if (blk->next) {
550 blk = blk->next;
551 i = 0;
552 } else {
553 i = blk->n;
554 }
555 nghttp2_ksl_it_init(&it, ksl, blk, i);
556 return it;
557 }
558 blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
559 }
560 }
561
nghttp2_ksl_lower_bound_compar(nghttp2_ksl * ksl,const nghttp2_ksl_key * key,nghttp2_ksl_compar compar)562 nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
563 const nghttp2_ksl_key *key,
564 nghttp2_ksl_compar compar) {
565 nghttp2_ksl_blk *blk = ksl->head;
566 nghttp2_ksl_it it;
567 size_t i;
568
569 for (;;) {
570 i = ksl_bsearch(ksl, blk, key, compar);
571
572 if (blk->leaf) {
573 if (i == blk->n && blk->next) {
574 blk = blk->next;
575 i = 0;
576 }
577 nghttp2_ksl_it_init(&it, ksl, blk, i);
578 return it;
579 }
580
581 if (i == blk->n) {
582 /* This happens if descendant has smaller key. Fast forward to
583 find last node in this subtree. */
584 for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
585 ;
586 if (blk->next) {
587 blk = blk->next;
588 i = 0;
589 } else {
590 i = blk->n;
591 }
592 nghttp2_ksl_it_init(&it, ksl, blk, i);
593 return it;
594 }
595 blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
596 }
597 }
598
nghttp2_ksl_update_key(nghttp2_ksl * ksl,const nghttp2_ksl_key * old_key,const nghttp2_ksl_key * new_key)599 void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
600 const nghttp2_ksl_key *new_key) {
601 nghttp2_ksl_blk *blk = ksl->head;
602 nghttp2_ksl_node *node;
603 size_t i;
604
605 for (;;) {
606 i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
607
608 assert(i < blk->n);
609 node = nghttp2_ksl_nth_node(ksl, blk, i);
610
611 if (blk->leaf) {
612 assert(key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key));
613 ksl_node_set_key(ksl, node, new_key);
614 return;
615 }
616
617 if (key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key) ||
618 ksl->compar((nghttp2_ksl_key *)node->key, new_key)) {
619 ksl_node_set_key(ksl, node, new_key);
620 }
621
622 blk = node->blk;
623 }
624 }
625
ksl_print(nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t level)626 static void ksl_print(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t level) {
627 size_t i;
628 nghttp2_ksl_node *node;
629
630 fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n);
631
632 if (blk->leaf) {
633 for (i = 0; i < blk->n; ++i) {
634 node = nghttp2_ksl_nth_node(ksl, blk, i);
635 fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
636 }
637 fprintf(stderr, "\n");
638 return;
639 }
640
641 for (i = 0; i < blk->n; ++i) {
642 ksl_print(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
643 }
644 }
645
nghttp2_ksl_len(nghttp2_ksl * ksl)646 size_t nghttp2_ksl_len(nghttp2_ksl *ksl) { return ksl->n; }
647
nghttp2_ksl_clear(nghttp2_ksl * ksl)648 void nghttp2_ksl_clear(nghttp2_ksl *ksl) {
649 size_t i;
650 nghttp2_ksl_blk *head;
651
652 if (!ksl->head->leaf) {
653 for (i = 0; i < ksl->head->n; ++i) {
654 ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, ksl->head, i)->blk);
655 }
656 }
657
658 ksl->front = ksl->back = ksl->head;
659 ksl->n = 0;
660
661 head = ksl->head;
662
663 head->next = head->prev = NULL;
664 head->n = 0;
665 head->leaf = 1;
666 }
667
nghttp2_ksl_print(nghttp2_ksl * ksl)668 void nghttp2_ksl_print(nghttp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); }
669
nghttp2_ksl_begin(const nghttp2_ksl * ksl)670 nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl) {
671 nghttp2_ksl_it it;
672 nghttp2_ksl_it_init(&it, ksl, ksl->front, 0);
673 return it;
674 }
675
nghttp2_ksl_end(const nghttp2_ksl * ksl)676 nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl) {
677 nghttp2_ksl_it it;
678 nghttp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
679 return it;
680 }
681
nghttp2_ksl_it_init(nghttp2_ksl_it * it,const nghttp2_ksl * ksl,nghttp2_ksl_blk * blk,size_t i)682 void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
683 nghttp2_ksl_blk *blk, size_t i) {
684 it->ksl = ksl;
685 it->blk = blk;
686 it->i = i;
687 }
688
nghttp2_ksl_it_get(const nghttp2_ksl_it * it)689 void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it) {
690 assert(it->i < it->blk->n);
691 return nghttp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
692 }
693
nghttp2_ksl_it_prev(nghttp2_ksl_it * it)694 void nghttp2_ksl_it_prev(nghttp2_ksl_it *it) {
695 assert(!nghttp2_ksl_it_begin(it));
696
697 if (it->i == 0) {
698 it->blk = it->blk->prev;
699 it->i = it->blk->n - 1;
700 } else {
701 --it->i;
702 }
703 }
704
nghttp2_ksl_it_begin(const nghttp2_ksl_it * it)705 int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it) {
706 return it->i == 0 && it->blk->prev == NULL;
707 }
708