123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- /*
- * nghttp3
- *
- * Copyright (c) 2019 nghttp3 contributors
- * Copyright (c) 2018 ngtcp2 contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #ifndef NGHTTP3_KSL_H
- #define NGHTTP3_KSL_H
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif /* defined(HAVE_CONFIG_H) */
- #include <stdlib.h>
- #include <nghttp3/nghttp3.h>
- #include "nghttp3_objalloc.h"
- #define NGHTTP3_KSL_DEGR 16
- /* NGHTTP3_KSL_MAX_NBLK is the maximum number of nodes which a single
- block can contain. */
- #define NGHTTP3_KSL_MAX_NBLK (2 * NGHTTP3_KSL_DEGR - 1)
- /* NGHTTP3_KSL_MIN_NBLK is the minimum number of nodes which a single
- block other than root must contain. */
- #define NGHTTP3_KSL_MIN_NBLK (NGHTTP3_KSL_DEGR - 1)
- /*
- * nghttp3_ksl_key represents key in nghttp3_ksl.
- */
- typedef void nghttp3_ksl_key;
- typedef struct nghttp3_ksl_node nghttp3_ksl_node;
- typedef struct nghttp3_ksl_blk nghttp3_ksl_blk;
- /*
- * nghttp3_ksl_node is a node which contains either nghttp3_ksl_blk or
- * opaque data. If a node is an internal node, it contains
- * nghttp3_ksl_blk. Otherwise, it has data. The key is stored at the
- * location starting at key.
- */
- struct nghttp3_ksl_node {
- union {
- nghttp3_ksl_blk *blk;
- void *data;
- };
- union {
- uint64_t align;
- /* key is a buffer to include key associated to this node.
- Because the length of key is unknown until nghttp3_ksl_init is
- called, the actual buffer will be allocated after this
- field. */
- uint8_t key[1];
- };
- };
- /*
- * nghttp3_ksl_blk contains nghttp3_ksl_node objects.
- */
- struct nghttp3_ksl_blk {
- union {
- struct {
- /* next points to the next block if leaf field is nonzero. */
- nghttp3_ksl_blk *next;
- /* prev points to the previous block if leaf field is
- nonzero. */
- nghttp3_ksl_blk *prev;
- /* n is the number of nodes this object contains in nodes. */
- uint32_t n;
- /* leaf is nonzero if this block contains leaf nodes. */
- uint32_t leaf;
- union {
- uint64_t align;
- /* nodes is a buffer to contain NGHTTP3_KSL_MAX_NBLK
- nghttp3_ksl_node objects. Because nghttp3_ksl_node object
- is allocated along with the additional variable length key
- storage, the size of buffer is unknown until
- nghttp3_ksl_init is called. */
- uint8_t nodes[1];
- };
- };
- nghttp3_opl_entry oplent;
- };
- };
- nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent)
- /*
- * nghttp3_ksl_compar is a function type which returns nonzero if key
- * |lhs| should be placed before |rhs|. It returns 0 otherwise.
- */
- typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs,
- const nghttp3_ksl_key *rhs);
- typedef struct nghttp3_ksl nghttp3_ksl;
- /*
- * nghttp3_ksl_search is a function to search for the first element in
- * |blk|->nodes which is not ordered before |key|. It returns the
- * index of such element. It returns |blk|->n if there is no such
- * element.
- */
- typedef size_t (*nghttp3_ksl_search)(const nghttp3_ksl *ksl,
- nghttp3_ksl_blk *blk,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_search_def is a macro to implement nghttp3_ksl_search
- * with COMPAR which is supposed to be nghttp3_ksl_compar.
- */
- #define nghttp3_ksl_search_def(NAME, COMPAR) \
- static size_t ksl_##NAME##_search(const nghttp3_ksl *ksl, \
- nghttp3_ksl_blk *blk, \
- const nghttp3_ksl_key *key) { \
- size_t i; \
- nghttp3_ksl_node *node; \
- \
- for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes; \
- i < blk->n && COMPAR((nghttp3_ksl_key *)node->key, key); ++i, \
- node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \
- ; \
- \
- return i; \
- }
- typedef struct nghttp3_ksl_it nghttp3_ksl_it;
- /*
- * nghttp3_ksl_it is a bidirectional iterator to iterate nodes.
- */
- struct nghttp3_ksl_it {
- const nghttp3_ksl *ksl;
- nghttp3_ksl_blk *blk;
- size_t i;
- };
- /*
- * nghttp3_ksl is a deterministic paged skip list.
- */
- struct nghttp3_ksl {
- nghttp3_objalloc blkalloc;
- /* head points to the root block. */
- nghttp3_ksl_blk *head;
- /* front points to the first leaf block. */
- nghttp3_ksl_blk *front;
- /* back points to the last leaf block. */
- nghttp3_ksl_blk *back;
- nghttp3_ksl_compar compar;
- nghttp3_ksl_search search;
- /* n is the number of elements stored. */
- size_t n;
- /* keylen is the size of key */
- size_t keylen;
- /* nodelen is the actual size of nghttp3_ksl_node including key
- storage. */
- size_t nodelen;
- };
- /*
- * nghttp3_ksl_init initializes |ksl|. |compar| specifies compare
- * function. |search| is a search function which must use |compar|.
- * |keylen| is the length of key and must be at least
- * sizeof(uint64_t).
- */
- void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
- nghttp3_ksl_search search, size_t keylen,
- const nghttp3_mem *mem);
- /*
- * nghttp3_ksl_free frees resources allocated for |ksl|. If |ksl| is
- * NULL, this function does nothing. It does not free the memory
- * region pointed by |ksl| itself.
- */
- void nghttp3_ksl_free(nghttp3_ksl *ksl);
- /*
- * nghttp3_ksl_insert inserts |key| with its associated |data|. On
- * successful insertion, the iterator points to the inserted node is
- * stored in |*it| if |it| is not NULL.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP3_ERR_NOMEM
- * Out of memory.
- * NGHTTP3_ERR_INVALID_ARGUMENT
- * |key| already exists.
- */
- int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
- const nghttp3_ksl_key *key, void *data);
- /*
- * nghttp3_ksl_remove removes the |key| from |ksl|.
- *
- * This function assigns the iterator to |*it|, which points to the
- * node which is located at the right next of the removed node if |it|
- * is not NULL. If |key| is not found, no deletion takes place and
- * the return value of nghttp3_ksl_end(ksl) is assigned to |*it| if
- * |it| is not NULL.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP3_ERR_INVALID_ARGUMENT
- * |key| does not exist.
- */
- int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_remove_hint removes the |key| from |ksl|. |hint| must
- * point to the same node denoted by |key|. |hint| is used to remove
- * a node efficiently in some cases. Other than that, it behaves
- * exactly like nghttp3_ksl_remove. |it| and |hint| can point to the
- * same object.
- */
- int nghttp3_ksl_remove_hint(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
- const nghttp3_ksl_it *hint,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_lower_bound returns the iterator which points to the
- * first node which has the key which is equal to |key| or the last
- * node which satisfies !compar(&node->key, key). If there is no such
- * node, it returns the iterator which satisfies
- * nghttp3_ksl_it_end(it) != 0.
- */
- nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_lower_bound_search works like nghttp3_ksl_lower_bound,
- * but it takes custom function |search| to do lower bound search.
- */
- nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl,
- const nghttp3_ksl_key *key,
- nghttp3_ksl_search search);
- /*
- * nghttp3_ksl_update_key replaces the key of nodes which has
- * |old_key| with |new_key|. |new_key| must be strictly greater than
- * the previous node and strictly smaller than the next node.
- */
- void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
- const nghttp3_ksl_key *new_key);
- /*
- * nghttp3_ksl_begin returns the iterator which points to the first
- * node. If there is no node in |ksl|, it returns the iterator which
- * satisfies both nghttp3_ksl_it_begin(it) != 0 and
- * nghttp3_ksl_it_end(it) != 0.
- */
- nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl);
- /*
- * nghttp3_ksl_end returns the iterator which points to the node
- * following the last node. The returned object satisfies
- * nghttp3_ksl_it_end(). If there is no node in |ksl|, it returns the
- * iterator which satisfies nghttp3_ksl_it_begin(it) != 0 and
- * nghttp3_ksl_it_end(it) != 0.
- */
- nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl);
- /*
- * nghttp3_ksl_len returns the number of elements stored in |ksl|.
- */
- size_t nghttp3_ksl_len(const nghttp3_ksl *ksl);
- /*
- * nghttp3_ksl_clear removes all elements stored in |ksl|.
- */
- void nghttp3_ksl_clear(nghttp3_ksl *ksl);
- /*
- * nghttp3_ksl_nth_node returns the |n|th node under |blk|.
- */
- #define nghttp3_ksl_nth_node(KSL, BLK, N) \
- ((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
- #ifndef WIN32
- /*
- * nghttp3_ksl_print prints its internal state in stderr. It assumes
- * that the key is of type int64_t. This function should be used for
- * the debugging purpose only.
- */
- void nghttp3_ksl_print(const nghttp3_ksl *ksl);
- #endif /* !defined(WIN32) */
- /*
- * nghttp3_ksl_it_init initializes |it|.
- */
- void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
- nghttp3_ksl_blk *blk, size_t i);
- /*
- * nghttp3_ksl_it_get returns the data associated to the node which
- * |it| points to. It is undefined to call this function when
- * nghttp3_ksl_it_end(it) returns nonzero.
- */
- #define nghttp3_ksl_it_get(IT) \
- nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
- /*
- * nghttp3_ksl_it_next advances the iterator by one. It is undefined
- * if this function is called when nghttp3_ksl_it_end(it) returns
- * nonzero.
- */
- #define nghttp3_ksl_it_next(IT) \
- (++(IT)->i == (IT)->blk->n && (IT)->blk->next \
- ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
- : 0)
- /*
- * nghttp3_ksl_it_prev moves backward the iterator by one. It is
- * undefined if this function is called when nghttp3_ksl_it_begin(it)
- * returns nonzero.
- */
- void nghttp3_ksl_it_prev(nghttp3_ksl_it *it);
- /*
- * nghttp3_ksl_it_end returns nonzero if |it| points to the one beyond
- * the last node.
- */
- #define nghttp3_ksl_it_end(IT) \
- ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
- /*
- * nghttp3_ksl_it_begin returns nonzero if |it| points to the first
- * node. |it| might satisfy both nghttp3_ksl_it_begin(it) != 0 and
- * nghttp3_ksl_it_end(it) != 0 if the skip list has no node.
- */
- int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it);
- /*
- * nghttp3_ksl_key returns the key of the node which |it| points to.
- * It is undefined to call this function when nghttp3_ksl_it_end(it)
- * returns nonzero.
- */
- #define nghttp3_ksl_it_key(IT) \
- ((nghttp3_ksl_key *)nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
- /*
- * nghttp3_ksl_range_compar is an implementation of
- * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range
- * object, and the function returns nonzero if ((const nghttp3_range
- * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin.
- */
- int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
- const nghttp3_ksl_key *rhs);
- /*
- * nghttp3_ksl_range_search is an implementation of nghttp3_ksl_search
- * that uses nghttp3_ksl_range_compar.
- */
- size_t nghttp3_ksl_range_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_range_exclusive_compar is an implementation of
- * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range
- * object, and the function returns nonzero if ((const nghttp3_range
- * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin, and the 2
- * ranges do not intersect.
- */
- int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
- const nghttp3_ksl_key *rhs);
- /*
- * nghttp3_ksl_range_exclusive_search is an implementation of
- * nghttp3_ksl_search that uses nghttp3_ksl_range_exclusive_compar.
- */
- size_t nghttp3_ksl_range_exclusive_search(const nghttp3_ksl *ksl,
- nghttp3_ksl_blk *blk,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_uint64_less is an implementation of nghttp3_ksl_compar.
- * |lhs| and |rhs| must point to uint64_t objects, and the function
- * returns nonzero if *(uint64_t *)|lhs| < *(uint64_t *)|rhs|.
- */
- int nghttp3_ksl_uint64_less(const nghttp3_ksl_key *lhs,
- const nghttp3_ksl_key *rhs);
- /*
- * nghttp3_ksl_uint64_less_search is an implementation of
- * nghttp3_ksl_search that uses nghttp3_ksl_uint64_less.
- */
- size_t nghttp3_ksl_uint64_less_search(const nghttp3_ksl *ksl,
- nghttp3_ksl_blk *blk,
- const nghttp3_ksl_key *key);
- /*
- * nghttp3_ksl_int64_greater is an implementation of
- * nghttp3_ksl_compar. |lhs| and |rhs| must point to int64_t objects,
- * and the function returns nonzero if *(int64_t *)|lhs| > *(int64_t
- * *)|rhs|.
- */
- int nghttp3_ksl_int64_greater(const nghttp3_ksl_key *lhs,
- const nghttp3_ksl_key *rhs);
- /*
- * nghttp3_ksl_int64_greater_search is an implementation of
- * nghttp3_ksl_search that uses nghttp3_ksl_int64_greater.
- */
- size_t nghttp3_ksl_int64_greater_search(const nghttp3_ksl *ksl,
- nghttp3_ksl_blk *blk,
- const nghttp3_ksl_key *key);
- #endif /* !defined(NGHTTP3_KSL_H) */
|