• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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