1 /*
2 * nghttp3
3 *
4 * Copyright (c) 2019 nghttp3 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 "nghttp3_ksl.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <stdio.h>
32
33 #include "nghttp3_macro.h"
34 #include "nghttp3_mem.h"
35 #include "nghttp3_range.h"
36
37 static nghttp3_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}};
38
ksl_nodelen(size_t keylen)39 static size_t ksl_nodelen(size_t keylen) {
40 return (sizeof(nghttp3_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) &
41 ~(uintptr_t)0xfu;
42 }
43
ksl_blklen(size_t nodelen)44 static size_t ksl_blklen(size_t nodelen) {
45 return sizeof(nghttp3_ksl_blk) + nodelen * NGHTTP3_KSL_MAX_NBLK -
46 sizeof(uint64_t);
47 }
48
49 /*
50 * ksl_node_set_key sets |key| to |node|.
51 */
ksl_node_set_key(nghttp3_ksl * ksl,nghttp3_ksl_node * node,const void * key)52 static void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node,
53 const void *key) {
54 memcpy(node->key, key, ksl->keylen);
55 }
56
nghttp3_ksl_init(nghttp3_ksl * ksl,nghttp3_ksl_compar compar,size_t keylen,const nghttp3_mem * mem)57 void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
58 size_t keylen, const nghttp3_mem *mem) {
59 size_t nodelen = ksl_nodelen(keylen);
60
61 nghttp3_objalloc_init(&ksl->blkalloc,
62 ((ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu) * 8,
63 mem);
64
65 ksl->head = NULL;
66 ksl->front = ksl->back = NULL;
67 ksl->compar = compar;
68 ksl->keylen = keylen;
69 ksl->nodelen = nodelen;
70 ksl->n = 0;
71 }
72
ksl_blk_objalloc_new(nghttp3_ksl * ksl)73 static nghttp3_ksl_blk *ksl_blk_objalloc_new(nghttp3_ksl *ksl) {
74 return nghttp3_objalloc_ksl_blk_len_get(&ksl->blkalloc,
75 ksl_blklen(ksl->nodelen));
76 }
77
ksl_blk_objalloc_del(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk)78 static void ksl_blk_objalloc_del(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
79 nghttp3_objalloc_ksl_blk_release(&ksl->blkalloc, blk);
80 }
81
ksl_head_init(nghttp3_ksl * ksl)82 static int ksl_head_init(nghttp3_ksl *ksl) {
83 nghttp3_ksl_blk *head = ksl_blk_objalloc_new(ksl);
84 if (!head) {
85 return NGHTTP3_ERR_NOMEM;
86 }
87
88 head->next = head->prev = NULL;
89 head->n = 0;
90 head->leaf = 1;
91
92 ksl->head = head;
93 ksl->front = ksl->back = head;
94
95 return 0;
96 }
97
98 #ifdef NOMEMPOOL
99 /*
100 * ksl_free_blk frees |blk| recursively.
101 */
ksl_free_blk(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk)102 static void ksl_free_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
103 size_t i;
104
105 if (!blk->leaf) {
106 for (i = 0; i < blk->n; ++i) {
107 ksl_free_blk(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk);
108 }
109 }
110
111 ksl_blk_objalloc_del(ksl, blk);
112 }
113 #endif /* NOMEMPOOL */
114
nghttp3_ksl_free(nghttp3_ksl * ksl)115 void nghttp3_ksl_free(nghttp3_ksl *ksl) {
116 if (!ksl || !ksl->head) {
117 return;
118 }
119
120 #ifdef NOMEMPOOL
121 ksl_free_blk(ksl, ksl->head);
122 #endif /* NOMEMPOOL */
123
124 nghttp3_objalloc_free(&ksl->blkalloc);
125 }
126
127 /*
128 * ksl_split_blk splits |blk| into 2 nghttp3_ksl_blk objects. The new
129 * nghttp3_ksl_blk is always the "right" block.
130 *
131 * It returns the pointer to the nghttp3_ksl_blk created which is the
132 * located at the right of |blk|, or NULL which indicates out of
133 * memory error.
134 */
ksl_split_blk(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk)135 static nghttp3_ksl_blk *ksl_split_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
136 nghttp3_ksl_blk *rblk;
137
138 rblk = ksl_blk_objalloc_new(ksl);
139 if (rblk == NULL) {
140 return NULL;
141 }
142
143 rblk->next = blk->next;
144 blk->next = rblk;
145 if (rblk->next) {
146 rblk->next->prev = rblk;
147 } else if (ksl->back == blk) {
148 ksl->back = rblk;
149 }
150 rblk->prev = blk;
151 rblk->leaf = blk->leaf;
152
153 rblk->n = blk->n / 2;
154
155 memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
156 ksl->nodelen * rblk->n);
157
158 blk->n -= rblk->n;
159
160 assert(blk->n >= NGHTTP3_KSL_MIN_NBLK);
161 assert(rblk->n >= NGHTTP3_KSL_MIN_NBLK);
162
163 return rblk;
164 }
165
166 /*
167 * ksl_split_node splits a node included in |blk| at the position |i|
168 * into 2 adjacent nodes. The new node is always inserted at the
169 * position |i+1|.
170 *
171 * It returns 0 if it succeeds, or one of the following negative error
172 * codes:
173 *
174 * NGHTTP3_ERR_NOMEM
175 * Out of memory.
176 */
ksl_split_node(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)177 static int ksl_split_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
178 nghttp3_ksl_node *node;
179 nghttp3_ksl_blk *lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk, *rblk;
180
181 rblk = ksl_split_blk(ksl, lblk);
182 if (rblk == NULL) {
183 return NGHTTP3_ERR_NOMEM;
184 }
185
186 memmove(blk->nodes + (i + 2) * ksl->nodelen,
187 blk->nodes + (i + 1) * ksl->nodelen,
188 ksl->nodelen * (blk->n - (i + 1)));
189
190 node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
191 node->blk = rblk;
192 ++blk->n;
193 ksl_node_set_key(ksl, node,
194 nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
195
196 node = nghttp3_ksl_nth_node(ksl, blk, i);
197 ksl_node_set_key(ksl, node,
198 nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
199
200 return 0;
201 }
202
203 /*
204 * ksl_split_head splits a head (root) block. It increases the height
205 * of skip list by 1.
206 *
207 * It returns 0 if it succeeds, or one of the following negative error
208 * codes:
209 *
210 * NGHTTP3_ERR_NOMEM
211 * Out of memory.
212 */
ksl_split_head(nghttp3_ksl * ksl)213 static int ksl_split_head(nghttp3_ksl *ksl) {
214 nghttp3_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
215 nghttp3_ksl_node *node;
216
217 rblk = ksl_split_blk(ksl, ksl->head);
218 if (rblk == NULL) {
219 return NGHTTP3_ERR_NOMEM;
220 }
221
222 lblk = ksl->head;
223
224 nhead = ksl_blk_objalloc_new(ksl);
225 if (nhead == NULL) {
226 ksl_blk_objalloc_del(ksl, rblk);
227 return NGHTTP3_ERR_NOMEM;
228 }
229 nhead->next = nhead->prev = NULL;
230 nhead->n = 2;
231 nhead->leaf = 0;
232
233 node = nghttp3_ksl_nth_node(ksl, nhead, 0);
234 ksl_node_set_key(ksl, node,
235 nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
236 node->blk = lblk;
237
238 node = nghttp3_ksl_nth_node(ksl, nhead, 1);
239 ksl_node_set_key(ksl, node,
240 nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
241 node->blk = rblk;
242
243 ksl->head = nhead;
244
245 return 0;
246 }
247
248 /*
249 * insert_node inserts a node whose key is |key| with the associated
250 * |data| at the index of |i|. This function assumes that the number
251 * of nodes contained by |blk| is strictly less than
252 * NGHTTP3_KSL_MAX_NBLK.
253 */
ksl_insert_node(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i,const nghttp3_ksl_key * key,void * data)254 static void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i,
255 const nghttp3_ksl_key *key, void *data) {
256 nghttp3_ksl_node *node;
257
258 assert(blk->n < NGHTTP3_KSL_MAX_NBLK);
259
260 memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
261 ksl->nodelen * (blk->n - i));
262
263 node = nghttp3_ksl_nth_node(ksl, blk, i);
264 ksl_node_set_key(ksl, node, key);
265 node->data = data;
266
267 ++blk->n;
268 }
269
ksl_bsearch(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,const nghttp3_ksl_key * key,nghttp3_ksl_compar compar)270 static size_t ksl_bsearch(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
271 const nghttp3_ksl_key *key,
272 nghttp3_ksl_compar compar) {
273 size_t i;
274 nghttp3_ksl_node *node;
275
276 for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes;
277 i < blk->n && compar((nghttp3_ksl_key *)node->key, key);
278 ++i, node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen))
279 ;
280
281 return i;
282 }
283
nghttp3_ksl_insert(nghttp3_ksl * ksl,nghttp3_ksl_it * it,const nghttp3_ksl_key * key,void * data)284 int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
285 const nghttp3_ksl_key *key, void *data) {
286 nghttp3_ksl_blk *blk;
287 nghttp3_ksl_node *node;
288 size_t i;
289 int rv;
290
291 if (!ksl->head) {
292 rv = ksl_head_init(ksl);
293 if (rv != 0) {
294 return rv;
295 }
296 }
297
298 blk = ksl->head;
299
300 if (blk->n == NGHTTP3_KSL_MAX_NBLK) {
301 rv = ksl_split_head(ksl);
302 if (rv != 0) {
303 return rv;
304 }
305 blk = ksl->head;
306 }
307
308 for (;;) {
309 i = ksl_bsearch(ksl, blk, key, ksl->compar);
310
311 if (blk->leaf) {
312 if (i < blk->n &&
313 !ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
314 if (it) {
315 *it = nghttp3_ksl_end(ksl);
316 }
317 return NGHTTP3_ERR_INVALID_ARGUMENT;
318 }
319 ksl_insert_node(ksl, blk, i, key, data);
320 ++ksl->n;
321 if (it) {
322 nghttp3_ksl_it_init(it, ksl, blk, i);
323 }
324 return 0;
325 }
326
327 if (i == blk->n) {
328 /* This insertion extends the largest key in this subtree. */
329 for (; !blk->leaf;) {
330 node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
331 if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
332 rv = ksl_split_node(ksl, blk, blk->n - 1);
333 if (rv != 0) {
334 return rv;
335 }
336 node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
337 }
338 ksl_node_set_key(ksl, node, key);
339 blk = node->blk;
340 }
341 ksl_insert_node(ksl, blk, blk->n, key, data);
342 ++ksl->n;
343 if (it) {
344 nghttp3_ksl_it_init(it, ksl, blk, blk->n - 1);
345 }
346 return 0;
347 }
348
349 node = nghttp3_ksl_nth_node(ksl, blk, i);
350
351 if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
352 rv = ksl_split_node(ksl, blk, i);
353 if (rv != 0) {
354 return rv;
355 }
356 if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
357 node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
358 if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
359 ksl_node_set_key(ksl, node, key);
360 }
361 }
362 }
363
364 blk = node->blk;
365 }
366 }
367
368 /*
369 * ksl_remove_node removes the node included in |blk| at the index of
370 * |i|.
371 */
ksl_remove_node(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)372 static void ksl_remove_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
373 memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
374 ksl->nodelen * (blk->n - (i + 1)));
375
376 --blk->n;
377 }
378
379 /*
380 * ksl_merge_node merges 2 nodes which are the nodes at the index of
381 * |i| and |i + 1|.
382 *
383 * If |blk| is the direct descendant of head (root) block and the head
384 * block contains just 2 nodes, the merged block becomes head block,
385 * which decreases the height of |ksl| by 1.
386 *
387 * This function returns the pointer to the merged block.
388 */
ksl_merge_node(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)389 static nghttp3_ksl_blk *ksl_merge_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
390 size_t i) {
391 nghttp3_ksl_blk *lblk, *rblk;
392
393 assert(i + 1 < blk->n);
394
395 lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
396 rblk = nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk;
397
398 assert(lblk->n + rblk->n < NGHTTP3_KSL_MAX_NBLK);
399
400 memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
401 ksl->nodelen * rblk->n);
402
403 lblk->n += rblk->n;
404 lblk->next = rblk->next;
405 if (lblk->next) {
406 lblk->next->prev = lblk;
407 } else if (ksl->back == rblk) {
408 ksl->back = lblk;
409 }
410
411 ksl_blk_objalloc_del(ksl, rblk);
412
413 if (ksl->head == blk && blk->n == 2) {
414 ksl_blk_objalloc_del(ksl, ksl->head);
415 ksl->head = lblk;
416 } else {
417 ksl_remove_node(ksl, blk, i + 1);
418 ksl_node_set_key(ksl, nghttp3_ksl_nth_node(ksl, blk, i),
419 nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
420 }
421
422 return lblk;
423 }
424
425 /*
426 * ksl_shift_left moves the first nodes in blk->nodes[i]->blk->nodes
427 * to blk->nodes[i - 1]->blk->nodes in a manner that they have the
428 * same amount of nodes as much as possible.
429 */
ksl_shift_left(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)430 static void ksl_shift_left(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
431 nghttp3_ksl_node *lnode, *rnode;
432 size_t n;
433
434 assert(i > 0);
435
436 lnode = nghttp3_ksl_nth_node(ksl, blk, i - 1);
437 rnode = nghttp3_ksl_nth_node(ksl, blk, i);
438
439 assert(lnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
440 assert(rnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
441
442 n = (lnode->blk->n + rnode->blk->n + 1) / 2 - lnode->blk->n;
443
444 assert(n > 0);
445 assert(lnode->blk->n <= NGHTTP3_KSL_MAX_NBLK - n);
446 assert(rnode->blk->n >= NGHTTP3_KSL_MIN_NBLK + n);
447
448 memcpy(lnode->blk->nodes + ksl->nodelen * lnode->blk->n, rnode->blk->nodes,
449 ksl->nodelen * n);
450
451 lnode->blk->n += (uint32_t)n;
452 rnode->blk->n -= (uint32_t)n;
453
454 ksl_node_set_key(
455 ksl, lnode,
456 nghttp3_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
457
458 memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen * n,
459 ksl->nodelen * rnode->blk->n);
460 }
461
462 /*
463 * ksl_shift_right moves the last nodes in blk->nodes[i]->blk->nodes
464 * to blk->nodes[i + 1]->blk->nodes in a manner that they have the
465 * same amount of nodes as much as possible..
466 */
ksl_shift_right(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)467 static void ksl_shift_right(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
468 nghttp3_ksl_node *lnode, *rnode;
469 size_t n;
470
471 assert(i < blk->n - 1);
472
473 lnode = nghttp3_ksl_nth_node(ksl, blk, i);
474 rnode = nghttp3_ksl_nth_node(ksl, blk, i + 1);
475
476 assert(lnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
477 assert(rnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
478
479 n = (lnode->blk->n + rnode->blk->n + 1) / 2 - rnode->blk->n;
480
481 assert(n > 0);
482 assert(lnode->blk->n >= NGHTTP3_KSL_MIN_NBLK + n);
483 assert(rnode->blk->n <= NGHTTP3_KSL_MAX_NBLK - n);
484
485 memmove(rnode->blk->nodes + ksl->nodelen * n, rnode->blk->nodes,
486 ksl->nodelen * rnode->blk->n);
487
488 rnode->blk->n += (uint32_t)n;
489 lnode->blk->n -= (uint32_t)n;
490
491 memcpy(rnode->blk->nodes, lnode->blk->nodes + ksl->nodelen * lnode->blk->n,
492 ksl->nodelen * n);
493
494 ksl_node_set_key(
495 ksl, lnode,
496 nghttp3_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
497 }
498
499 /*
500 * key_equal returns nonzero if |lhs| and |rhs| are equal using the
501 * function |compar|.
502 */
key_equal(nghttp3_ksl_compar compar,const nghttp3_ksl_key * lhs,const nghttp3_ksl_key * rhs)503 static int key_equal(nghttp3_ksl_compar compar, const nghttp3_ksl_key *lhs,
504 const nghttp3_ksl_key *rhs) {
505 return !compar(lhs, rhs) && !compar(rhs, lhs);
506 }
507
nghttp3_ksl_remove_hint(nghttp3_ksl * ksl,nghttp3_ksl_it * it,const nghttp3_ksl_it * hint,const nghttp3_ksl_key * key)508 int nghttp3_ksl_remove_hint(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
509 const nghttp3_ksl_it *hint,
510 const nghttp3_ksl_key *key) {
511 nghttp3_ksl_blk *blk = hint->blk;
512
513 assert(ksl->head);
514
515 if (blk->n <= NGHTTP3_KSL_MIN_NBLK) {
516 return nghttp3_ksl_remove(ksl, it, key);
517 }
518
519 ksl_remove_node(ksl, blk, hint->i);
520
521 --ksl->n;
522
523 if (it) {
524 if (hint->i == blk->n && blk->next) {
525 nghttp3_ksl_it_init(it, ksl, blk->next, 0);
526 } else {
527 nghttp3_ksl_it_init(it, ksl, blk, hint->i);
528 }
529 }
530
531 return 0;
532 }
533
nghttp3_ksl_remove(nghttp3_ksl * ksl,nghttp3_ksl_it * it,const nghttp3_ksl_key * key)534 int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
535 const nghttp3_ksl_key *key) {
536 nghttp3_ksl_blk *blk = ksl->head;
537 nghttp3_ksl_node *node;
538 size_t i;
539
540 if (!ksl->head) {
541 return NGHTTP3_ERR_INVALID_ARGUMENT;
542 }
543
544 if (!blk->leaf && blk->n == 2 &&
545 nghttp3_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP3_KSL_MIN_NBLK &&
546 nghttp3_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP3_KSL_MIN_NBLK) {
547 blk = ksl_merge_node(ksl, ksl->head, 0);
548 }
549
550 for (;;) {
551 i = ksl_bsearch(ksl, blk, key, ksl->compar);
552
553 if (i == blk->n) {
554 if (it) {
555 *it = nghttp3_ksl_end(ksl);
556 }
557 return NGHTTP3_ERR_INVALID_ARGUMENT;
558 }
559
560 if (blk->leaf) {
561 if (ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
562 if (it) {
563 *it = nghttp3_ksl_end(ksl);
564 }
565 return NGHTTP3_ERR_INVALID_ARGUMENT;
566 }
567 ksl_remove_node(ksl, blk, i);
568 --ksl->n;
569 if (it) {
570 if (blk->n == i && blk->next) {
571 nghttp3_ksl_it_init(it, ksl, blk->next, 0);
572 } else {
573 nghttp3_ksl_it_init(it, ksl, blk, i);
574 }
575 }
576 return 0;
577 }
578
579 node = nghttp3_ksl_nth_node(ksl, blk, i);
580
581 if (node->blk->n > NGHTTP3_KSL_MIN_NBLK) {
582 blk = node->blk;
583 continue;
584 }
585
586 assert(node->blk->n == NGHTTP3_KSL_MIN_NBLK);
587
588 if (i + 1 < blk->n &&
589 nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
590 ksl_shift_left(ksl, blk, i + 1);
591 blk = node->blk;
592 continue;
593 }
594
595 if (i > 0 &&
596 nghttp3_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
597 ksl_shift_right(ksl, blk, i - 1);
598 blk = node->blk;
599 continue;
600 }
601
602 if (i + 1 < blk->n) {
603 blk = ksl_merge_node(ksl, blk, i);
604 continue;
605 }
606
607 assert(i > 0);
608
609 blk = ksl_merge_node(ksl, blk, i - 1);
610 }
611 }
612
nghttp3_ksl_lower_bound(nghttp3_ksl * ksl,const nghttp3_ksl_key * key)613 nghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl,
614 const nghttp3_ksl_key *key) {
615 nghttp3_ksl_blk *blk = ksl->head;
616 nghttp3_ksl_it it;
617 size_t i;
618
619 if (!blk) {
620 nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
621 return it;
622 }
623
624 for (;;) {
625 i = ksl_bsearch(ksl, blk, key, ksl->compar);
626
627 if (blk->leaf) {
628 if (i == blk->n && blk->next) {
629 blk = blk->next;
630 i = 0;
631 }
632 nghttp3_ksl_it_init(&it, ksl, blk, i);
633 return it;
634 }
635
636 if (i == blk->n) {
637 /* This happens if descendant has smaller key. Fast forward to
638 find last node in this subtree. */
639 for (; !blk->leaf; blk = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
640 ;
641 if (blk->next) {
642 blk = blk->next;
643 i = 0;
644 } else {
645 i = blk->n;
646 }
647 nghttp3_ksl_it_init(&it, ksl, blk, i);
648 return it;
649 }
650 blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
651 }
652 }
653
nghttp3_ksl_lower_bound_compar(nghttp3_ksl * ksl,const nghttp3_ksl_key * key,nghttp3_ksl_compar compar)654 nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl,
655 const nghttp3_ksl_key *key,
656 nghttp3_ksl_compar compar) {
657 nghttp3_ksl_blk *blk = ksl->head;
658 nghttp3_ksl_it it;
659 size_t i;
660
661 if (!blk) {
662 nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
663 return it;
664 }
665
666 for (;;) {
667 i = ksl_bsearch(ksl, blk, key, compar);
668
669 if (blk->leaf) {
670 if (i == blk->n && blk->next) {
671 blk = blk->next;
672 i = 0;
673 }
674 nghttp3_ksl_it_init(&it, ksl, blk, i);
675 return it;
676 }
677
678 if (i == blk->n) {
679 /* This happens if descendant has smaller key. Fast forward to
680 find last node in this subtree. */
681 for (; !blk->leaf; blk = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
682 ;
683 if (blk->next) {
684 blk = blk->next;
685 i = 0;
686 } else {
687 i = blk->n;
688 }
689 nghttp3_ksl_it_init(&it, ksl, blk, i);
690 return it;
691 }
692 blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
693 }
694 }
695
nghttp3_ksl_update_key(nghttp3_ksl * ksl,const nghttp3_ksl_key * old_key,const nghttp3_ksl_key * new_key)696 void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
697 const nghttp3_ksl_key *new_key) {
698 nghttp3_ksl_blk *blk = ksl->head;
699 nghttp3_ksl_node *node;
700 size_t i;
701
702 assert(ksl->head);
703
704 for (;;) {
705 i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
706
707 assert(i < blk->n);
708 node = nghttp3_ksl_nth_node(ksl, blk, i);
709
710 if (blk->leaf) {
711 assert(key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key));
712 ksl_node_set_key(ksl, node, new_key);
713 return;
714 }
715
716 if (key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key) ||
717 ksl->compar((nghttp3_ksl_key *)node->key, new_key)) {
718 ksl_node_set_key(ksl, node, new_key);
719 }
720
721 blk = node->blk;
722 }
723 }
724
ksl_print(nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t level)725 static void ksl_print(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t level) {
726 size_t i;
727 nghttp3_ksl_node *node;
728
729 fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
730
731 if (blk->leaf) {
732 for (i = 0; i < blk->n; ++i) {
733 node = nghttp3_ksl_nth_node(ksl, blk, i);
734 fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
735 }
736 fprintf(stderr, "\n");
737 return;
738 }
739
740 for (i = 0; i < blk->n; ++i) {
741 ksl_print(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk, level + 1);
742 }
743 }
744
nghttp3_ksl_len(nghttp3_ksl * ksl)745 size_t nghttp3_ksl_len(nghttp3_ksl *ksl) { return ksl->n; }
746
nghttp3_ksl_clear(nghttp3_ksl * ksl)747 void nghttp3_ksl_clear(nghttp3_ksl *ksl) {
748 if (!ksl->head) {
749 return;
750 }
751
752 #ifdef NOMEMPOOL
753 ksl_free_blk(ksl, ksl->head);
754 #endif /* NOMEMPOOL */
755
756 ksl->front = ksl->back = ksl->head = NULL;
757 ksl->n = 0;
758
759 nghttp3_objalloc_clear(&ksl->blkalloc);
760 }
761
nghttp3_ksl_print(nghttp3_ksl * ksl)762 void nghttp3_ksl_print(nghttp3_ksl *ksl) {
763 if (!ksl->head) {
764 return;
765 }
766
767 ksl_print(ksl, ksl->head, 0);
768 }
769
nghttp3_ksl_begin(const nghttp3_ksl * ksl)770 nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl) {
771 nghttp3_ksl_it it;
772
773 if (ksl->head) {
774 nghttp3_ksl_it_init(&it, ksl, ksl->front, 0);
775 } else {
776 nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
777 }
778
779 return it;
780 }
781
nghttp3_ksl_end(const nghttp3_ksl * ksl)782 nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl) {
783 nghttp3_ksl_it it;
784
785 if (ksl->head) {
786 nghttp3_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
787 } else {
788 nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
789 }
790
791 return it;
792 }
793
nghttp3_ksl_it_init(nghttp3_ksl_it * it,const nghttp3_ksl * ksl,nghttp3_ksl_blk * blk,size_t i)794 void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
795 nghttp3_ksl_blk *blk, size_t i) {
796 it->ksl = ksl;
797 it->blk = blk;
798 it->i = i;
799 }
800
nghttp3_ksl_it_prev(nghttp3_ksl_it * it)801 void nghttp3_ksl_it_prev(nghttp3_ksl_it *it) {
802 assert(!nghttp3_ksl_it_begin(it));
803
804 if (it->i == 0) {
805 it->blk = it->blk->prev;
806 it->i = it->blk->n - 1;
807 } else {
808 --it->i;
809 }
810 }
811
nghttp3_ksl_it_begin(const nghttp3_ksl_it * it)812 int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it) {
813 return it->i == 0 && it->blk->prev == NULL;
814 }
815
nghttp3_ksl_range_compar(const nghttp3_ksl_key * lhs,const nghttp3_ksl_key * rhs)816 int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
817 const nghttp3_ksl_key *rhs) {
818 const nghttp3_range *a = lhs, *b = rhs;
819 return a->begin < b->begin;
820 }
821
nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key * lhs,const nghttp3_ksl_key * rhs)822 int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
823 const nghttp3_ksl_key *rhs) {
824 const nghttp3_range *a = lhs, *b = rhs;
825 return a->begin < b->begin &&
826 !(nghttp3_max(a->begin, b->begin) < nghttp3_min(a->end, b->end));
827 }
828