11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * nghttp3
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Copyright (c) 2019 nghttp3 contributors
51cb0ef41Sopenharmony_ci * Copyright (c) 2018 ngtcp2 contributors
61cb0ef41Sopenharmony_ci *
71cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
81cb0ef41Sopenharmony_ci * a copy of this software and associated documentation files (the
91cb0ef41Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
101cb0ef41Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
111cb0ef41Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
121cb0ef41Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
131cb0ef41Sopenharmony_ci * the following conditions:
141cb0ef41Sopenharmony_ci *
151cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be
161cb0ef41Sopenharmony_ci * included in all copies or substantial portions of the Software.
171cb0ef41Sopenharmony_ci *
181cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
191cb0ef41Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
201cb0ef41Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
211cb0ef41Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
221cb0ef41Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
231cb0ef41Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
241cb0ef41Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "nghttp3_ksl.h"
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci#include <stdlib.h>
291cb0ef41Sopenharmony_ci#include <string.h>
301cb0ef41Sopenharmony_ci#include <assert.h>
311cb0ef41Sopenharmony_ci#include <stdio.h>
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci#include "nghttp3_macro.h"
341cb0ef41Sopenharmony_ci#include "nghttp3_mem.h"
351cb0ef41Sopenharmony_ci#include "nghttp3_range.h"
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_cistatic nghttp3_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}};
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cistatic size_t ksl_nodelen(size_t keylen) {
401cb0ef41Sopenharmony_ci  return (sizeof(nghttp3_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) &
411cb0ef41Sopenharmony_ci         ~(uintptr_t)0xfu;
421cb0ef41Sopenharmony_ci}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cistatic size_t ksl_blklen(size_t nodelen) {
451cb0ef41Sopenharmony_ci  return sizeof(nghttp3_ksl_blk) + nodelen * NGHTTP3_KSL_MAX_NBLK -
461cb0ef41Sopenharmony_ci         sizeof(uint64_t);
471cb0ef41Sopenharmony_ci}
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci/*
501cb0ef41Sopenharmony_ci * ksl_node_set_key sets |key| to |node|.
511cb0ef41Sopenharmony_ci */
521cb0ef41Sopenharmony_cistatic void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node,
531cb0ef41Sopenharmony_ci                             const void *key) {
541cb0ef41Sopenharmony_ci  memcpy(node->key, key, ksl->keylen);
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_civoid nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
581cb0ef41Sopenharmony_ci                      size_t keylen, const nghttp3_mem *mem) {
591cb0ef41Sopenharmony_ci  size_t nodelen = ksl_nodelen(keylen);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  nghttp3_objalloc_init(&ksl->blkalloc,
621cb0ef41Sopenharmony_ci                        ((ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu) * 8,
631cb0ef41Sopenharmony_ci                        mem);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  ksl->head = NULL;
661cb0ef41Sopenharmony_ci  ksl->front = ksl->back = NULL;
671cb0ef41Sopenharmony_ci  ksl->compar = compar;
681cb0ef41Sopenharmony_ci  ksl->keylen = keylen;
691cb0ef41Sopenharmony_ci  ksl->nodelen = nodelen;
701cb0ef41Sopenharmony_ci  ksl->n = 0;
711cb0ef41Sopenharmony_ci}
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cistatic nghttp3_ksl_blk *ksl_blk_objalloc_new(nghttp3_ksl *ksl) {
741cb0ef41Sopenharmony_ci  return nghttp3_objalloc_ksl_blk_len_get(&ksl->blkalloc,
751cb0ef41Sopenharmony_ci                                          ksl_blklen(ksl->nodelen));
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_cistatic void ksl_blk_objalloc_del(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
791cb0ef41Sopenharmony_ci  nghttp3_objalloc_ksl_blk_release(&ksl->blkalloc, blk);
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_cistatic int ksl_head_init(nghttp3_ksl *ksl) {
831cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *head = ksl_blk_objalloc_new(ksl);
841cb0ef41Sopenharmony_ci  if (!head) {
851cb0ef41Sopenharmony_ci    return NGHTTP3_ERR_NOMEM;
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  head->next = head->prev = NULL;
891cb0ef41Sopenharmony_ci  head->n = 0;
901cb0ef41Sopenharmony_ci  head->leaf = 1;
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  ksl->head = head;
931cb0ef41Sopenharmony_ci  ksl->front = ksl->back = head;
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  return 0;
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci#ifdef NOMEMPOOL
991cb0ef41Sopenharmony_ci/*
1001cb0ef41Sopenharmony_ci * ksl_free_blk frees |blk| recursively.
1011cb0ef41Sopenharmony_ci */
1021cb0ef41Sopenharmony_cistatic void ksl_free_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
1031cb0ef41Sopenharmony_ci  size_t i;
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  if (!blk->leaf) {
1061cb0ef41Sopenharmony_ci    for (i = 0; i < blk->n; ++i) {
1071cb0ef41Sopenharmony_ci      ksl_free_blk(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk);
1081cb0ef41Sopenharmony_ci    }
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  ksl_blk_objalloc_del(ksl, blk);
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci#endif /* NOMEMPOOL */
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_civoid nghttp3_ksl_free(nghttp3_ksl *ksl) {
1161cb0ef41Sopenharmony_ci  if (!ksl || !ksl->head) {
1171cb0ef41Sopenharmony_ci    return;
1181cb0ef41Sopenharmony_ci  }
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci#ifdef NOMEMPOOL
1211cb0ef41Sopenharmony_ci  ksl_free_blk(ksl, ksl->head);
1221cb0ef41Sopenharmony_ci#endif /* NOMEMPOOL */
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  nghttp3_objalloc_free(&ksl->blkalloc);
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci/*
1281cb0ef41Sopenharmony_ci * ksl_split_blk splits |blk| into 2 nghttp3_ksl_blk objects.  The new
1291cb0ef41Sopenharmony_ci * nghttp3_ksl_blk is always the "right" block.
1301cb0ef41Sopenharmony_ci *
1311cb0ef41Sopenharmony_ci * It returns the pointer to the nghttp3_ksl_blk created which is the
1321cb0ef41Sopenharmony_ci * located at the right of |blk|, or NULL which indicates out of
1331cb0ef41Sopenharmony_ci * memory error.
1341cb0ef41Sopenharmony_ci */
1351cb0ef41Sopenharmony_cistatic nghttp3_ksl_blk *ksl_split_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
1361cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *rblk;
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  rblk = ksl_blk_objalloc_new(ksl);
1391cb0ef41Sopenharmony_ci  if (rblk == NULL) {
1401cb0ef41Sopenharmony_ci    return NULL;
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  rblk->next = blk->next;
1441cb0ef41Sopenharmony_ci  blk->next = rblk;
1451cb0ef41Sopenharmony_ci  if (rblk->next) {
1461cb0ef41Sopenharmony_ci    rblk->next->prev = rblk;
1471cb0ef41Sopenharmony_ci  } else if (ksl->back == blk) {
1481cb0ef41Sopenharmony_ci    ksl->back = rblk;
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci  rblk->prev = blk;
1511cb0ef41Sopenharmony_ci  rblk->leaf = blk->leaf;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  rblk->n = blk->n / 2;
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
1561cb0ef41Sopenharmony_ci         ksl->nodelen * rblk->n);
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  blk->n -= rblk->n;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  assert(blk->n >= NGHTTP3_KSL_MIN_NBLK);
1611cb0ef41Sopenharmony_ci  assert(rblk->n >= NGHTTP3_KSL_MIN_NBLK);
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  return rblk;
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci/*
1671cb0ef41Sopenharmony_ci * ksl_split_node splits a node included in |blk| at the position |i|
1681cb0ef41Sopenharmony_ci * into 2 adjacent nodes.  The new node is always inserted at the
1691cb0ef41Sopenharmony_ci * position |i+1|.
1701cb0ef41Sopenharmony_ci *
1711cb0ef41Sopenharmony_ci * It returns 0 if it succeeds, or one of the following negative error
1721cb0ef41Sopenharmony_ci * codes:
1731cb0ef41Sopenharmony_ci *
1741cb0ef41Sopenharmony_ci * NGHTTP3_ERR_NOMEM
1751cb0ef41Sopenharmony_ci *   Out of memory.
1761cb0ef41Sopenharmony_ci */
1771cb0ef41Sopenharmony_cistatic int ksl_split_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
1781cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
1791cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk, *rblk;
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  rblk = ksl_split_blk(ksl, lblk);
1821cb0ef41Sopenharmony_ci  if (rblk == NULL) {
1831cb0ef41Sopenharmony_ci    return NGHTTP3_ERR_NOMEM;
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  memmove(blk->nodes + (i + 2) * ksl->nodelen,
1871cb0ef41Sopenharmony_ci          blk->nodes + (i + 1) * ksl->nodelen,
1881cb0ef41Sopenharmony_ci          ksl->nodelen * (blk->n - (i + 1)));
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
1911cb0ef41Sopenharmony_ci  node->blk = rblk;
1921cb0ef41Sopenharmony_ci  ++blk->n;
1931cb0ef41Sopenharmony_ci  ksl_node_set_key(ksl, node,
1941cb0ef41Sopenharmony_ci                   nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci  node = nghttp3_ksl_nth_node(ksl, blk, i);
1971cb0ef41Sopenharmony_ci  ksl_node_set_key(ksl, node,
1981cb0ef41Sopenharmony_ci                   nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  return 0;
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci/*
2041cb0ef41Sopenharmony_ci * ksl_split_head splits a head (root) block.  It increases the height
2051cb0ef41Sopenharmony_ci * of skip list by 1.
2061cb0ef41Sopenharmony_ci *
2071cb0ef41Sopenharmony_ci * It returns 0 if it succeeds, or one of the following negative error
2081cb0ef41Sopenharmony_ci * codes:
2091cb0ef41Sopenharmony_ci *
2101cb0ef41Sopenharmony_ci * NGHTTP3_ERR_NOMEM
2111cb0ef41Sopenharmony_ci *   Out of memory.
2121cb0ef41Sopenharmony_ci */
2131cb0ef41Sopenharmony_cistatic int ksl_split_head(nghttp3_ksl *ksl) {
2141cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
2151cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  rblk = ksl_split_blk(ksl, ksl->head);
2181cb0ef41Sopenharmony_ci  if (rblk == NULL) {
2191cb0ef41Sopenharmony_ci    return NGHTTP3_ERR_NOMEM;
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  lblk = ksl->head;
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  nhead = ksl_blk_objalloc_new(ksl);
2251cb0ef41Sopenharmony_ci  if (nhead == NULL) {
2261cb0ef41Sopenharmony_ci    ksl_blk_objalloc_del(ksl, rblk);
2271cb0ef41Sopenharmony_ci    return NGHTTP3_ERR_NOMEM;
2281cb0ef41Sopenharmony_ci  }
2291cb0ef41Sopenharmony_ci  nhead->next = nhead->prev = NULL;
2301cb0ef41Sopenharmony_ci  nhead->n = 2;
2311cb0ef41Sopenharmony_ci  nhead->leaf = 0;
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  node = nghttp3_ksl_nth_node(ksl, nhead, 0);
2341cb0ef41Sopenharmony_ci  ksl_node_set_key(ksl, node,
2351cb0ef41Sopenharmony_ci                   nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
2361cb0ef41Sopenharmony_ci  node->blk = lblk;
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  node = nghttp3_ksl_nth_node(ksl, nhead, 1);
2391cb0ef41Sopenharmony_ci  ksl_node_set_key(ksl, node,
2401cb0ef41Sopenharmony_ci                   nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
2411cb0ef41Sopenharmony_ci  node->blk = rblk;
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci  ksl->head = nhead;
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  return 0;
2461cb0ef41Sopenharmony_ci}
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci/*
2491cb0ef41Sopenharmony_ci * insert_node inserts a node whose key is |key| with the associated
2501cb0ef41Sopenharmony_ci * |data| at the index of |i|.  This function assumes that the number
2511cb0ef41Sopenharmony_ci * of nodes contained by |blk| is strictly less than
2521cb0ef41Sopenharmony_ci * NGHTTP3_KSL_MAX_NBLK.
2531cb0ef41Sopenharmony_ci */
2541cb0ef41Sopenharmony_cistatic void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i,
2551cb0ef41Sopenharmony_ci                            const nghttp3_ksl_key *key, void *data) {
2561cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci  assert(blk->n < NGHTTP3_KSL_MAX_NBLK);
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci  memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
2611cb0ef41Sopenharmony_ci          ksl->nodelen * (blk->n - i));
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  node = nghttp3_ksl_nth_node(ksl, blk, i);
2641cb0ef41Sopenharmony_ci  ksl_node_set_key(ksl, node, key);
2651cb0ef41Sopenharmony_ci  node->data = data;
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci  ++blk->n;
2681cb0ef41Sopenharmony_ci}
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_cistatic size_t ksl_bsearch(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
2711cb0ef41Sopenharmony_ci                          const nghttp3_ksl_key *key,
2721cb0ef41Sopenharmony_ci                          nghttp3_ksl_compar compar) {
2731cb0ef41Sopenharmony_ci  size_t i;
2741cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci  for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes;
2771cb0ef41Sopenharmony_ci       i < blk->n && compar((nghttp3_ksl_key *)node->key, key);
2781cb0ef41Sopenharmony_ci       ++i, node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen))
2791cb0ef41Sopenharmony_ci    ;
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  return i;
2821cb0ef41Sopenharmony_ci}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ciint nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
2851cb0ef41Sopenharmony_ci                       const nghttp3_ksl_key *key, void *data) {
2861cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk;
2871cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
2881cb0ef41Sopenharmony_ci  size_t i;
2891cb0ef41Sopenharmony_ci  int rv;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  if (!ksl->head) {
2921cb0ef41Sopenharmony_ci    rv = ksl_head_init(ksl);
2931cb0ef41Sopenharmony_ci    if (rv != 0) {
2941cb0ef41Sopenharmony_ci      return rv;
2951cb0ef41Sopenharmony_ci    }
2961cb0ef41Sopenharmony_ci  }
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci  blk = ksl->head;
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  if (blk->n == NGHTTP3_KSL_MAX_NBLK) {
3011cb0ef41Sopenharmony_ci    rv = ksl_split_head(ksl);
3021cb0ef41Sopenharmony_ci    if (rv != 0) {
3031cb0ef41Sopenharmony_ci      return rv;
3041cb0ef41Sopenharmony_ci    }
3051cb0ef41Sopenharmony_ci    blk = ksl->head;
3061cb0ef41Sopenharmony_ci  }
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  for (;;) {
3091cb0ef41Sopenharmony_ci    i = ksl_bsearch(ksl, blk, key, ksl->compar);
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci    if (blk->leaf) {
3121cb0ef41Sopenharmony_ci      if (i < blk->n &&
3131cb0ef41Sopenharmony_ci          !ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
3141cb0ef41Sopenharmony_ci        if (it) {
3151cb0ef41Sopenharmony_ci          *it = nghttp3_ksl_end(ksl);
3161cb0ef41Sopenharmony_ci        }
3171cb0ef41Sopenharmony_ci        return NGHTTP3_ERR_INVALID_ARGUMENT;
3181cb0ef41Sopenharmony_ci      }
3191cb0ef41Sopenharmony_ci      ksl_insert_node(ksl, blk, i, key, data);
3201cb0ef41Sopenharmony_ci      ++ksl->n;
3211cb0ef41Sopenharmony_ci      if (it) {
3221cb0ef41Sopenharmony_ci        nghttp3_ksl_it_init(it, ksl, blk, i);
3231cb0ef41Sopenharmony_ci      }
3241cb0ef41Sopenharmony_ci      return 0;
3251cb0ef41Sopenharmony_ci    }
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci    if (i == blk->n) {
3281cb0ef41Sopenharmony_ci      /* This insertion extends the largest key in this subtree. */
3291cb0ef41Sopenharmony_ci      for (; !blk->leaf;) {
3301cb0ef41Sopenharmony_ci        node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
3311cb0ef41Sopenharmony_ci        if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
3321cb0ef41Sopenharmony_ci          rv = ksl_split_node(ksl, blk, blk->n - 1);
3331cb0ef41Sopenharmony_ci          if (rv != 0) {
3341cb0ef41Sopenharmony_ci            return rv;
3351cb0ef41Sopenharmony_ci          }
3361cb0ef41Sopenharmony_ci          node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
3371cb0ef41Sopenharmony_ci        }
3381cb0ef41Sopenharmony_ci        ksl_node_set_key(ksl, node, key);
3391cb0ef41Sopenharmony_ci        blk = node->blk;
3401cb0ef41Sopenharmony_ci      }
3411cb0ef41Sopenharmony_ci      ksl_insert_node(ksl, blk, blk->n, key, data);
3421cb0ef41Sopenharmony_ci      ++ksl->n;
3431cb0ef41Sopenharmony_ci      if (it) {
3441cb0ef41Sopenharmony_ci        nghttp3_ksl_it_init(it, ksl, blk, blk->n - 1);
3451cb0ef41Sopenharmony_ci      }
3461cb0ef41Sopenharmony_ci      return 0;
3471cb0ef41Sopenharmony_ci    }
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci    node = nghttp3_ksl_nth_node(ksl, blk, i);
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci    if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
3521cb0ef41Sopenharmony_ci      rv = ksl_split_node(ksl, blk, i);
3531cb0ef41Sopenharmony_ci      if (rv != 0) {
3541cb0ef41Sopenharmony_ci        return rv;
3551cb0ef41Sopenharmony_ci      }
3561cb0ef41Sopenharmony_ci      if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
3571cb0ef41Sopenharmony_ci        node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
3581cb0ef41Sopenharmony_ci        if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
3591cb0ef41Sopenharmony_ci          ksl_node_set_key(ksl, node, key);
3601cb0ef41Sopenharmony_ci        }
3611cb0ef41Sopenharmony_ci      }
3621cb0ef41Sopenharmony_ci    }
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci    blk = node->blk;
3651cb0ef41Sopenharmony_ci  }
3661cb0ef41Sopenharmony_ci}
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci/*
3691cb0ef41Sopenharmony_ci * ksl_remove_node removes the node included in |blk| at the index of
3701cb0ef41Sopenharmony_ci * |i|.
3711cb0ef41Sopenharmony_ci */
3721cb0ef41Sopenharmony_cistatic void ksl_remove_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
3731cb0ef41Sopenharmony_ci  memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
3741cb0ef41Sopenharmony_ci          ksl->nodelen * (blk->n - (i + 1)));
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci  --blk->n;
3771cb0ef41Sopenharmony_ci}
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci/*
3801cb0ef41Sopenharmony_ci * ksl_merge_node merges 2 nodes which are the nodes at the index of
3811cb0ef41Sopenharmony_ci * |i| and |i + 1|.
3821cb0ef41Sopenharmony_ci *
3831cb0ef41Sopenharmony_ci * If |blk| is the direct descendant of head (root) block and the head
3841cb0ef41Sopenharmony_ci * block contains just 2 nodes, the merged block becomes head block,
3851cb0ef41Sopenharmony_ci * which decreases the height of |ksl| by 1.
3861cb0ef41Sopenharmony_ci *
3871cb0ef41Sopenharmony_ci * This function returns the pointer to the merged block.
3881cb0ef41Sopenharmony_ci */
3891cb0ef41Sopenharmony_cistatic nghttp3_ksl_blk *ksl_merge_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
3901cb0ef41Sopenharmony_ci                                       size_t i) {
3911cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *lblk, *rblk;
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ci  assert(i + 1 < blk->n);
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ci  lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
3961cb0ef41Sopenharmony_ci  rblk = nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk;
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  assert(lblk->n + rblk->n < NGHTTP3_KSL_MAX_NBLK);
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci  memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
4011cb0ef41Sopenharmony_ci         ksl->nodelen * rblk->n);
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  lblk->n += rblk->n;
4041cb0ef41Sopenharmony_ci  lblk->next = rblk->next;
4051cb0ef41Sopenharmony_ci  if (lblk->next) {
4061cb0ef41Sopenharmony_ci    lblk->next->prev = lblk;
4071cb0ef41Sopenharmony_ci  } else if (ksl->back == rblk) {
4081cb0ef41Sopenharmony_ci    ksl->back = lblk;
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  ksl_blk_objalloc_del(ksl, rblk);
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci  if (ksl->head == blk && blk->n == 2) {
4141cb0ef41Sopenharmony_ci    ksl_blk_objalloc_del(ksl, ksl->head);
4151cb0ef41Sopenharmony_ci    ksl->head = lblk;
4161cb0ef41Sopenharmony_ci  } else {
4171cb0ef41Sopenharmony_ci    ksl_remove_node(ksl, blk, i + 1);
4181cb0ef41Sopenharmony_ci    ksl_node_set_key(ksl, nghttp3_ksl_nth_node(ksl, blk, i),
4191cb0ef41Sopenharmony_ci                     nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
4201cb0ef41Sopenharmony_ci  }
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci  return lblk;
4231cb0ef41Sopenharmony_ci}
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci/*
4261cb0ef41Sopenharmony_ci * ksl_shift_left moves the first nodes in blk->nodes[i]->blk->nodes
4271cb0ef41Sopenharmony_ci * to blk->nodes[i - 1]->blk->nodes in a manner that they have the
4281cb0ef41Sopenharmony_ci * same amount of nodes as much as possible.
4291cb0ef41Sopenharmony_ci */
4301cb0ef41Sopenharmony_cistatic void ksl_shift_left(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
4311cb0ef41Sopenharmony_ci  nghttp3_ksl_node *lnode, *rnode;
4321cb0ef41Sopenharmony_ci  size_t n;
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci  assert(i > 0);
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  lnode = nghttp3_ksl_nth_node(ksl, blk, i - 1);
4371cb0ef41Sopenharmony_ci  rnode = nghttp3_ksl_nth_node(ksl, blk, i);
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci  assert(lnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
4401cb0ef41Sopenharmony_ci  assert(rnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  n = (lnode->blk->n + rnode->blk->n + 1) / 2 - lnode->blk->n;
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci  assert(n > 0);
4451cb0ef41Sopenharmony_ci  assert(lnode->blk->n <= NGHTTP3_KSL_MAX_NBLK - n);
4461cb0ef41Sopenharmony_ci  assert(rnode->blk->n >= NGHTTP3_KSL_MIN_NBLK + n);
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci  memcpy(lnode->blk->nodes + ksl->nodelen * lnode->blk->n, rnode->blk->nodes,
4491cb0ef41Sopenharmony_ci         ksl->nodelen * n);
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci  lnode->blk->n += (uint32_t)n;
4521cb0ef41Sopenharmony_ci  rnode->blk->n -= (uint32_t)n;
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci  ksl_node_set_key(
4551cb0ef41Sopenharmony_ci      ksl, lnode,
4561cb0ef41Sopenharmony_ci      nghttp3_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci  memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen * n,
4591cb0ef41Sopenharmony_ci          ksl->nodelen * rnode->blk->n);
4601cb0ef41Sopenharmony_ci}
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci/*
4631cb0ef41Sopenharmony_ci * ksl_shift_right moves the last nodes in blk->nodes[i]->blk->nodes
4641cb0ef41Sopenharmony_ci * to blk->nodes[i + 1]->blk->nodes in a manner that they have the
4651cb0ef41Sopenharmony_ci * same amount of nodes as much as possible..
4661cb0ef41Sopenharmony_ci */
4671cb0ef41Sopenharmony_cistatic void ksl_shift_right(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
4681cb0ef41Sopenharmony_ci  nghttp3_ksl_node *lnode, *rnode;
4691cb0ef41Sopenharmony_ci  size_t n;
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci  assert(i < blk->n - 1);
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  lnode = nghttp3_ksl_nth_node(ksl, blk, i);
4741cb0ef41Sopenharmony_ci  rnode = nghttp3_ksl_nth_node(ksl, blk, i + 1);
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  assert(lnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
4771cb0ef41Sopenharmony_ci  assert(rnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  n = (lnode->blk->n + rnode->blk->n + 1) / 2 - rnode->blk->n;
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  assert(n > 0);
4821cb0ef41Sopenharmony_ci  assert(lnode->blk->n >= NGHTTP3_KSL_MIN_NBLK + n);
4831cb0ef41Sopenharmony_ci  assert(rnode->blk->n <= NGHTTP3_KSL_MAX_NBLK - n);
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci  memmove(rnode->blk->nodes + ksl->nodelen * n, rnode->blk->nodes,
4861cb0ef41Sopenharmony_ci          ksl->nodelen * rnode->blk->n);
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_ci  rnode->blk->n += (uint32_t)n;
4891cb0ef41Sopenharmony_ci  lnode->blk->n -= (uint32_t)n;
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_ci  memcpy(rnode->blk->nodes, lnode->blk->nodes + ksl->nodelen * lnode->blk->n,
4921cb0ef41Sopenharmony_ci         ksl->nodelen * n);
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci  ksl_node_set_key(
4951cb0ef41Sopenharmony_ci      ksl, lnode,
4961cb0ef41Sopenharmony_ci      nghttp3_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
4971cb0ef41Sopenharmony_ci}
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci/*
5001cb0ef41Sopenharmony_ci * key_equal returns nonzero if |lhs| and |rhs| are equal using the
5011cb0ef41Sopenharmony_ci * function |compar|.
5021cb0ef41Sopenharmony_ci */
5031cb0ef41Sopenharmony_cistatic int key_equal(nghttp3_ksl_compar compar, const nghttp3_ksl_key *lhs,
5041cb0ef41Sopenharmony_ci                     const nghttp3_ksl_key *rhs) {
5051cb0ef41Sopenharmony_ci  return !compar(lhs, rhs) && !compar(rhs, lhs);
5061cb0ef41Sopenharmony_ci}
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ciint nghttp3_ksl_remove_hint(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
5091cb0ef41Sopenharmony_ci                            const nghttp3_ksl_it *hint,
5101cb0ef41Sopenharmony_ci                            const nghttp3_ksl_key *key) {
5111cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk = hint->blk;
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci  assert(ksl->head);
5141cb0ef41Sopenharmony_ci
5151cb0ef41Sopenharmony_ci  if (blk->n <= NGHTTP3_KSL_MIN_NBLK) {
5161cb0ef41Sopenharmony_ci    return nghttp3_ksl_remove(ksl, it, key);
5171cb0ef41Sopenharmony_ci  }
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ci  ksl_remove_node(ksl, blk, hint->i);
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  --ksl->n;
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci  if (it) {
5241cb0ef41Sopenharmony_ci    if (hint->i == blk->n && blk->next) {
5251cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(it, ksl, blk->next, 0);
5261cb0ef41Sopenharmony_ci    } else {
5271cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(it, ksl, blk, hint->i);
5281cb0ef41Sopenharmony_ci    }
5291cb0ef41Sopenharmony_ci  }
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci  return 0;
5321cb0ef41Sopenharmony_ci}
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ciint nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
5351cb0ef41Sopenharmony_ci                       const nghttp3_ksl_key *key) {
5361cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk = ksl->head;
5371cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
5381cb0ef41Sopenharmony_ci  size_t i;
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci  if (!ksl->head) {
5411cb0ef41Sopenharmony_ci    return NGHTTP3_ERR_INVALID_ARGUMENT;
5421cb0ef41Sopenharmony_ci  }
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci  if (!blk->leaf && blk->n == 2 &&
5451cb0ef41Sopenharmony_ci      nghttp3_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP3_KSL_MIN_NBLK &&
5461cb0ef41Sopenharmony_ci      nghttp3_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP3_KSL_MIN_NBLK) {
5471cb0ef41Sopenharmony_ci    blk = ksl_merge_node(ksl, ksl->head, 0);
5481cb0ef41Sopenharmony_ci  }
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci  for (;;) {
5511cb0ef41Sopenharmony_ci    i = ksl_bsearch(ksl, blk, key, ksl->compar);
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci    if (i == blk->n) {
5541cb0ef41Sopenharmony_ci      if (it) {
5551cb0ef41Sopenharmony_ci        *it = nghttp3_ksl_end(ksl);
5561cb0ef41Sopenharmony_ci      }
5571cb0ef41Sopenharmony_ci      return NGHTTP3_ERR_INVALID_ARGUMENT;
5581cb0ef41Sopenharmony_ci    }
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ci    if (blk->leaf) {
5611cb0ef41Sopenharmony_ci      if (ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
5621cb0ef41Sopenharmony_ci        if (it) {
5631cb0ef41Sopenharmony_ci          *it = nghttp3_ksl_end(ksl);
5641cb0ef41Sopenharmony_ci        }
5651cb0ef41Sopenharmony_ci        return NGHTTP3_ERR_INVALID_ARGUMENT;
5661cb0ef41Sopenharmony_ci      }
5671cb0ef41Sopenharmony_ci      ksl_remove_node(ksl, blk, i);
5681cb0ef41Sopenharmony_ci      --ksl->n;
5691cb0ef41Sopenharmony_ci      if (it) {
5701cb0ef41Sopenharmony_ci        if (blk->n == i && blk->next) {
5711cb0ef41Sopenharmony_ci          nghttp3_ksl_it_init(it, ksl, blk->next, 0);
5721cb0ef41Sopenharmony_ci        } else {
5731cb0ef41Sopenharmony_ci          nghttp3_ksl_it_init(it, ksl, blk, i);
5741cb0ef41Sopenharmony_ci        }
5751cb0ef41Sopenharmony_ci      }
5761cb0ef41Sopenharmony_ci      return 0;
5771cb0ef41Sopenharmony_ci    }
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci    node = nghttp3_ksl_nth_node(ksl, blk, i);
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci    if (node->blk->n > NGHTTP3_KSL_MIN_NBLK) {
5821cb0ef41Sopenharmony_ci      blk = node->blk;
5831cb0ef41Sopenharmony_ci      continue;
5841cb0ef41Sopenharmony_ci    }
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci    assert(node->blk->n == NGHTTP3_KSL_MIN_NBLK);
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_ci    if (i + 1 < blk->n &&
5891cb0ef41Sopenharmony_ci        nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
5901cb0ef41Sopenharmony_ci      ksl_shift_left(ksl, blk, i + 1);
5911cb0ef41Sopenharmony_ci      blk = node->blk;
5921cb0ef41Sopenharmony_ci      continue;
5931cb0ef41Sopenharmony_ci    }
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_ci    if (i > 0 &&
5961cb0ef41Sopenharmony_ci        nghttp3_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
5971cb0ef41Sopenharmony_ci      ksl_shift_right(ksl, blk, i - 1);
5981cb0ef41Sopenharmony_ci      blk = node->blk;
5991cb0ef41Sopenharmony_ci      continue;
6001cb0ef41Sopenharmony_ci    }
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci    if (i + 1 < blk->n) {
6031cb0ef41Sopenharmony_ci      blk = ksl_merge_node(ksl, blk, i);
6041cb0ef41Sopenharmony_ci      continue;
6051cb0ef41Sopenharmony_ci    }
6061cb0ef41Sopenharmony_ci
6071cb0ef41Sopenharmony_ci    assert(i > 0);
6081cb0ef41Sopenharmony_ci
6091cb0ef41Sopenharmony_ci    blk = ksl_merge_node(ksl, blk, i - 1);
6101cb0ef41Sopenharmony_ci  }
6111cb0ef41Sopenharmony_ci}
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_cinghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl,
6141cb0ef41Sopenharmony_ci                                       const nghttp3_ksl_key *key) {
6151cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk = ksl->head;
6161cb0ef41Sopenharmony_ci  nghttp3_ksl_it it;
6171cb0ef41Sopenharmony_ci  size_t i;
6181cb0ef41Sopenharmony_ci
6191cb0ef41Sopenharmony_ci  if (!blk) {
6201cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
6211cb0ef41Sopenharmony_ci    return it;
6221cb0ef41Sopenharmony_ci  }
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci  for (;;) {
6251cb0ef41Sopenharmony_ci    i = ksl_bsearch(ksl, blk, key, ksl->compar);
6261cb0ef41Sopenharmony_ci
6271cb0ef41Sopenharmony_ci    if (blk->leaf) {
6281cb0ef41Sopenharmony_ci      if (i == blk->n && blk->next) {
6291cb0ef41Sopenharmony_ci        blk = blk->next;
6301cb0ef41Sopenharmony_ci        i = 0;
6311cb0ef41Sopenharmony_ci      }
6321cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(&it, ksl, blk, i);
6331cb0ef41Sopenharmony_ci      return it;
6341cb0ef41Sopenharmony_ci    }
6351cb0ef41Sopenharmony_ci
6361cb0ef41Sopenharmony_ci    if (i == blk->n) {
6371cb0ef41Sopenharmony_ci      /* This happens if descendant has smaller key.  Fast forward to
6381cb0ef41Sopenharmony_ci         find last node in this subtree. */
6391cb0ef41Sopenharmony_ci      for (; !blk->leaf; blk = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
6401cb0ef41Sopenharmony_ci        ;
6411cb0ef41Sopenharmony_ci      if (blk->next) {
6421cb0ef41Sopenharmony_ci        blk = blk->next;
6431cb0ef41Sopenharmony_ci        i = 0;
6441cb0ef41Sopenharmony_ci      } else {
6451cb0ef41Sopenharmony_ci        i = blk->n;
6461cb0ef41Sopenharmony_ci      }
6471cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(&it, ksl, blk, i);
6481cb0ef41Sopenharmony_ci      return it;
6491cb0ef41Sopenharmony_ci    }
6501cb0ef41Sopenharmony_ci    blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
6511cb0ef41Sopenharmony_ci  }
6521cb0ef41Sopenharmony_ci}
6531cb0ef41Sopenharmony_ci
6541cb0ef41Sopenharmony_cinghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl,
6551cb0ef41Sopenharmony_ci                                              const nghttp3_ksl_key *key,
6561cb0ef41Sopenharmony_ci                                              nghttp3_ksl_compar compar) {
6571cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk = ksl->head;
6581cb0ef41Sopenharmony_ci  nghttp3_ksl_it it;
6591cb0ef41Sopenharmony_ci  size_t i;
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_ci  if (!blk) {
6621cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
6631cb0ef41Sopenharmony_ci    return it;
6641cb0ef41Sopenharmony_ci  }
6651cb0ef41Sopenharmony_ci
6661cb0ef41Sopenharmony_ci  for (;;) {
6671cb0ef41Sopenharmony_ci    i = ksl_bsearch(ksl, blk, key, compar);
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_ci    if (blk->leaf) {
6701cb0ef41Sopenharmony_ci      if (i == blk->n && blk->next) {
6711cb0ef41Sopenharmony_ci        blk = blk->next;
6721cb0ef41Sopenharmony_ci        i = 0;
6731cb0ef41Sopenharmony_ci      }
6741cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(&it, ksl, blk, i);
6751cb0ef41Sopenharmony_ci      return it;
6761cb0ef41Sopenharmony_ci    }
6771cb0ef41Sopenharmony_ci
6781cb0ef41Sopenharmony_ci    if (i == blk->n) {
6791cb0ef41Sopenharmony_ci      /* This happens if descendant has smaller key.  Fast forward to
6801cb0ef41Sopenharmony_ci         find last node in this subtree. */
6811cb0ef41Sopenharmony_ci      for (; !blk->leaf; blk = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
6821cb0ef41Sopenharmony_ci        ;
6831cb0ef41Sopenharmony_ci      if (blk->next) {
6841cb0ef41Sopenharmony_ci        blk = blk->next;
6851cb0ef41Sopenharmony_ci        i = 0;
6861cb0ef41Sopenharmony_ci      } else {
6871cb0ef41Sopenharmony_ci        i = blk->n;
6881cb0ef41Sopenharmony_ci      }
6891cb0ef41Sopenharmony_ci      nghttp3_ksl_it_init(&it, ksl, blk, i);
6901cb0ef41Sopenharmony_ci      return it;
6911cb0ef41Sopenharmony_ci    }
6921cb0ef41Sopenharmony_ci    blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
6931cb0ef41Sopenharmony_ci  }
6941cb0ef41Sopenharmony_ci}
6951cb0ef41Sopenharmony_ci
6961cb0ef41Sopenharmony_civoid nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
6971cb0ef41Sopenharmony_ci                            const nghttp3_ksl_key *new_key) {
6981cb0ef41Sopenharmony_ci  nghttp3_ksl_blk *blk = ksl->head;
6991cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
7001cb0ef41Sopenharmony_ci  size_t i;
7011cb0ef41Sopenharmony_ci
7021cb0ef41Sopenharmony_ci  assert(ksl->head);
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci  for (;;) {
7051cb0ef41Sopenharmony_ci    i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
7061cb0ef41Sopenharmony_ci
7071cb0ef41Sopenharmony_ci    assert(i < blk->n);
7081cb0ef41Sopenharmony_ci    node = nghttp3_ksl_nth_node(ksl, blk, i);
7091cb0ef41Sopenharmony_ci
7101cb0ef41Sopenharmony_ci    if (blk->leaf) {
7111cb0ef41Sopenharmony_ci      assert(key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key));
7121cb0ef41Sopenharmony_ci      ksl_node_set_key(ksl, node, new_key);
7131cb0ef41Sopenharmony_ci      return;
7141cb0ef41Sopenharmony_ci    }
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_ci    if (key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key) ||
7171cb0ef41Sopenharmony_ci        ksl->compar((nghttp3_ksl_key *)node->key, new_key)) {
7181cb0ef41Sopenharmony_ci      ksl_node_set_key(ksl, node, new_key);
7191cb0ef41Sopenharmony_ci    }
7201cb0ef41Sopenharmony_ci
7211cb0ef41Sopenharmony_ci    blk = node->blk;
7221cb0ef41Sopenharmony_ci  }
7231cb0ef41Sopenharmony_ci}
7241cb0ef41Sopenharmony_ci
7251cb0ef41Sopenharmony_cistatic void ksl_print(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t level) {
7261cb0ef41Sopenharmony_ci  size_t i;
7271cb0ef41Sopenharmony_ci  nghttp3_ksl_node *node;
7281cb0ef41Sopenharmony_ci
7291cb0ef41Sopenharmony_ci  fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci  if (blk->leaf) {
7321cb0ef41Sopenharmony_ci    for (i = 0; i < blk->n; ++i) {
7331cb0ef41Sopenharmony_ci      node = nghttp3_ksl_nth_node(ksl, blk, i);
7341cb0ef41Sopenharmony_ci      fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
7351cb0ef41Sopenharmony_ci    }
7361cb0ef41Sopenharmony_ci    fprintf(stderr, "\n");
7371cb0ef41Sopenharmony_ci    return;
7381cb0ef41Sopenharmony_ci  }
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ci  for (i = 0; i < blk->n; ++i) {
7411cb0ef41Sopenharmony_ci    ksl_print(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk, level + 1);
7421cb0ef41Sopenharmony_ci  }
7431cb0ef41Sopenharmony_ci}
7441cb0ef41Sopenharmony_ci
7451cb0ef41Sopenharmony_cisize_t nghttp3_ksl_len(nghttp3_ksl *ksl) { return ksl->n; }
7461cb0ef41Sopenharmony_ci
7471cb0ef41Sopenharmony_civoid nghttp3_ksl_clear(nghttp3_ksl *ksl) {
7481cb0ef41Sopenharmony_ci  if (!ksl->head) {
7491cb0ef41Sopenharmony_ci    return;
7501cb0ef41Sopenharmony_ci  }
7511cb0ef41Sopenharmony_ci
7521cb0ef41Sopenharmony_ci#ifdef NOMEMPOOL
7531cb0ef41Sopenharmony_ci  ksl_free_blk(ksl, ksl->head);
7541cb0ef41Sopenharmony_ci#endif /* NOMEMPOOL */
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_ci  ksl->front = ksl->back = ksl->head = NULL;
7571cb0ef41Sopenharmony_ci  ksl->n = 0;
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_ci  nghttp3_objalloc_clear(&ksl->blkalloc);
7601cb0ef41Sopenharmony_ci}
7611cb0ef41Sopenharmony_ci
7621cb0ef41Sopenharmony_civoid nghttp3_ksl_print(nghttp3_ksl *ksl) {
7631cb0ef41Sopenharmony_ci  if (!ksl->head) {
7641cb0ef41Sopenharmony_ci    return;
7651cb0ef41Sopenharmony_ci  }
7661cb0ef41Sopenharmony_ci
7671cb0ef41Sopenharmony_ci  ksl_print(ksl, ksl->head, 0);
7681cb0ef41Sopenharmony_ci}
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_cinghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl) {
7711cb0ef41Sopenharmony_ci  nghttp3_ksl_it it;
7721cb0ef41Sopenharmony_ci
7731cb0ef41Sopenharmony_ci  if (ksl->head) {
7741cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, ksl->front, 0);
7751cb0ef41Sopenharmony_ci  } else {
7761cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
7771cb0ef41Sopenharmony_ci  }
7781cb0ef41Sopenharmony_ci
7791cb0ef41Sopenharmony_ci  return it;
7801cb0ef41Sopenharmony_ci}
7811cb0ef41Sopenharmony_ci
7821cb0ef41Sopenharmony_cinghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl) {
7831cb0ef41Sopenharmony_ci  nghttp3_ksl_it it;
7841cb0ef41Sopenharmony_ci
7851cb0ef41Sopenharmony_ci  if (ksl->head) {
7861cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
7871cb0ef41Sopenharmony_ci  } else {
7881cb0ef41Sopenharmony_ci    nghttp3_ksl_it_init(&it, ksl, &null_blk, 0);
7891cb0ef41Sopenharmony_ci  }
7901cb0ef41Sopenharmony_ci
7911cb0ef41Sopenharmony_ci  return it;
7921cb0ef41Sopenharmony_ci}
7931cb0ef41Sopenharmony_ci
7941cb0ef41Sopenharmony_civoid nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
7951cb0ef41Sopenharmony_ci                         nghttp3_ksl_blk *blk, size_t i) {
7961cb0ef41Sopenharmony_ci  it->ksl = ksl;
7971cb0ef41Sopenharmony_ci  it->blk = blk;
7981cb0ef41Sopenharmony_ci  it->i = i;
7991cb0ef41Sopenharmony_ci}
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_civoid nghttp3_ksl_it_prev(nghttp3_ksl_it *it) {
8021cb0ef41Sopenharmony_ci  assert(!nghttp3_ksl_it_begin(it));
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_ci  if (it->i == 0) {
8051cb0ef41Sopenharmony_ci    it->blk = it->blk->prev;
8061cb0ef41Sopenharmony_ci    it->i = it->blk->n - 1;
8071cb0ef41Sopenharmony_ci  } else {
8081cb0ef41Sopenharmony_ci    --it->i;
8091cb0ef41Sopenharmony_ci  }
8101cb0ef41Sopenharmony_ci}
8111cb0ef41Sopenharmony_ci
8121cb0ef41Sopenharmony_ciint nghttp3_ksl_it_begin(const nghttp3_ksl_it *it) {
8131cb0ef41Sopenharmony_ci  return it->i == 0 && it->blk->prev == NULL;
8141cb0ef41Sopenharmony_ci}
8151cb0ef41Sopenharmony_ci
8161cb0ef41Sopenharmony_ciint nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
8171cb0ef41Sopenharmony_ci                             const nghttp3_ksl_key *rhs) {
8181cb0ef41Sopenharmony_ci  const nghttp3_range *a = lhs, *b = rhs;
8191cb0ef41Sopenharmony_ci  return a->begin < b->begin;
8201cb0ef41Sopenharmony_ci}
8211cb0ef41Sopenharmony_ci
8221cb0ef41Sopenharmony_ciint nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
8231cb0ef41Sopenharmony_ci                                       const nghttp3_ksl_key *rhs) {
8241cb0ef41Sopenharmony_ci  const nghttp3_range *a = lhs, *b = rhs;
8251cb0ef41Sopenharmony_ci  return a->begin < b->begin &&
8261cb0ef41Sopenharmony_ci         !(nghttp3_max(a->begin, b->begin) < nghttp3_min(a->end, b->end));
8271cb0ef41Sopenharmony_ci}
828