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