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 #ifndef NGHTTP2_KSL_H 27 #define NGHTTP2_KSL_H 28 29 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif /* HAVE_CONFIG_H */ 32 33 #include <stdlib.h> 34 35 #include <nghttp2/nghttp2.h> 36 37 /* 38 * Skip List using single key instead of range. 39 */ 40 41 #define NGHTTP2_KSL_DEGR 16 42 /* NGHTTP2_KSL_MAX_NBLK is the maximum number of nodes which a single 43 block can contain. */ 44 #define NGHTTP2_KSL_MAX_NBLK (2 * NGHTTP2_KSL_DEGR - 1) 45 /* NGHTTP2_KSL_MIN_NBLK is the minimum number of nodes which a single 46 block other than root must contains. */ 47 #define NGHTTP2_KSL_MIN_NBLK (NGHTTP2_KSL_DEGR - 1) 48 49 /* 50 * nghttp2_ksl_key represents key in nghttp2_ksl. 51 */ 52 typedef void nghttp2_ksl_key; 53 54 struct nghttp2_ksl_node; 55 typedef struct nghttp2_ksl_node nghttp2_ksl_node; 56 57 struct nghttp2_ksl_blk; 58 typedef struct nghttp2_ksl_blk nghttp2_ksl_blk; 59 60 /* 61 * nghttp2_ksl_node is a node which contains either nghttp2_ksl_blk or 62 * opaque data. If a node is an internal node, it contains 63 * nghttp2_ksl_blk. Otherwise, it has data. The key is stored at the 64 * location starting at key. 65 */ 66 struct nghttp2_ksl_node { 67 union { 68 nghttp2_ksl_blk *blk; 69 void *data; 70 }; 71 union { 72 uint64_t align; 73 /* key is a buffer to include key associated to this node. 74 Because the length of key is unknown until nghttp2_ksl_init is 75 called, the actual buffer will be allocated after this 76 field. */ 77 uint8_t key[1]; 78 }; 79 }; 80 81 /* 82 * nghttp2_ksl_blk contains nghttp2_ksl_node objects. 83 */ 84 struct nghttp2_ksl_blk { 85 /* next points to the next block if leaf field is nonzero. */ 86 nghttp2_ksl_blk *next; 87 /* prev points to the previous block if leaf field is nonzero. */ 88 nghttp2_ksl_blk *prev; 89 /* n is the number of nodes this object contains in nodes. */ 90 size_t n; 91 /* leaf is nonzero if this block contains leaf nodes. */ 92 int leaf; 93 union { 94 uint64_t align; 95 /* nodes is a buffer to contain NGHTTP2_KSL_MAX_NBLK 96 nghttp2_ksl_node objects. Because nghttp2_ksl_node object is 97 allocated along with the additional variable length key 98 storage, the size of buffer is unknown until nghttp2_ksl_init is 99 called. */ 100 uint8_t nodes[1]; 101 }; 102 }; 103 104 /* 105 * nghttp2_ksl_compar is a function type which returns nonzero if key 106 * |lhs| should be placed before |rhs|. It returns 0 otherwise. 107 */ 108 typedef int (*nghttp2_ksl_compar)(const nghttp2_ksl_key *lhs, 109 const nghttp2_ksl_key *rhs); 110 111 struct nghttp2_ksl; 112 typedef struct nghttp2_ksl nghttp2_ksl; 113 114 struct nghttp2_ksl_it; 115 typedef struct nghttp2_ksl_it nghttp2_ksl_it; 116 117 /* 118 * nghttp2_ksl_it is a forward iterator to iterate nodes. 119 */ 120 struct nghttp2_ksl_it { 121 const nghttp2_ksl *ksl; 122 nghttp2_ksl_blk *blk; 123 size_t i; 124 }; 125 126 /* 127 * nghttp2_ksl is a deterministic paged skip list. 128 */ 129 struct nghttp2_ksl { 130 /* head points to the root block. */ 131 nghttp2_ksl_blk *head; 132 /* front points to the first leaf block. */ 133 nghttp2_ksl_blk *front; 134 /* back points to the last leaf block. */ 135 nghttp2_ksl_blk *back; 136 nghttp2_ksl_compar compar; 137 size_t n; 138 /* keylen is the size of key */ 139 size_t keylen; 140 /* nodelen is the actual size of nghttp2_ksl_node including key 141 storage. */ 142 size_t nodelen; 143 nghttp2_mem *mem; 144 }; 145 146 /* 147 * nghttp2_ksl_init initializes |ksl|. |compar| specifies compare 148 * function. |keylen| is the length of key. 149 * 150 * It returns 0 if it succeeds, or one of the following negative error 151 * codes: 152 * 153 * NGHTTP2_ERR_NOMEM 154 * Out of memory. 155 */ 156 int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen, 157 nghttp2_mem *mem); 158 159 /* 160 * nghttp2_ksl_free frees resources allocated for |ksl|. If |ksl| is 161 * NULL, this function does nothing. It does not free the memory 162 * region pointed by |ksl| itself. 163 */ 164 void nghttp2_ksl_free(nghttp2_ksl *ksl); 165 166 /* 167 * nghttp2_ksl_insert inserts |key| with its associated |data|. On 168 * successful insertion, the iterator points to the inserted node is 169 * stored in |*it|. 170 * 171 * This function returns 0 if it succeeds, or one of the following 172 * negative error codes: 173 * 174 * NGHTTP2_ERR_NOMEM 175 * Out of memory. 176 * NGHTTP2_ERR_INVALID_ARGUMENT 177 * |key| already exists. 178 */ 179 int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it, 180 const nghttp2_ksl_key *key, void *data); 181 182 /* 183 * nghttp2_ksl_remove removes the |key| from |ksl|. 184 * 185 * This function assigns the iterator to |*it|, which points to the 186 * node which is located at the right next of the removed node if |it| 187 * is not NULL. If |key| is not found, no deletion takes place and 188 * the return value of nghttp2_ksl_end(ksl) is assigned to |*it|. 189 * 190 * This function returns 0 if it succeeds, or one of the following 191 * negative error codes: 192 * 193 * NGHTTP2_ERR_INVALID_ARGUMENT 194 * |key| does not exist. 195 */ 196 int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it, 197 const nghttp2_ksl_key *key); 198 199 /* 200 * nghttp2_ksl_lower_bound returns the iterator which points to the 201 * first node which has the key which is equal to |key| or the last 202 * node which satisfies !compar(&node->key, key). If there is no such 203 * node, it returns the iterator which satisfies nghttp2_ksl_it_end(it) 204 * != 0. 205 */ 206 nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl, 207 const nghttp2_ksl_key *key); 208 209 /* 210 * nghttp2_ksl_lower_bound_compar works like nghttp2_ksl_lower_bound, 211 * but it takes custom function |compar| to do lower bound search. 212 */ 213 nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl, 214 const nghttp2_ksl_key *key, 215 nghttp2_ksl_compar compar); 216 217 /* 218 * nghttp2_ksl_update_key replaces the key of nodes which has |old_key| 219 * with |new_key|. |new_key| must be strictly greater than the 220 * previous node and strictly smaller than the next node. 221 */ 222 void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key, 223 const nghttp2_ksl_key *new_key); 224 225 /* 226 * nghttp2_ksl_begin returns the iterator which points to the first 227 * node. If there is no node in |ksl|, it returns the iterator which 228 * satisfies nghttp2_ksl_it_end(it) != 0. 229 */ 230 nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl); 231 232 /* 233 * nghttp2_ksl_end returns the iterator which points to the node 234 * following the last node. The returned object satisfies 235 * nghttp2_ksl_it_end(). If there is no node in |ksl|, it returns the 236 * iterator which satisfies nghttp2_ksl_it_begin(it) != 0. 237 */ 238 nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl); 239 240 /* 241 * nghttp2_ksl_len returns the number of elements stored in |ksl|. 242 */ 243 size_t nghttp2_ksl_len(nghttp2_ksl *ksl); 244 245 /* 246 * nghttp2_ksl_clear removes all elements stored in |ksl|. 247 */ 248 void nghttp2_ksl_clear(nghttp2_ksl *ksl); 249 250 /* 251 * nghttp2_ksl_nth_node returns the |n|th node under |blk|. 252 */ 253 #define nghttp2_ksl_nth_node(KSL, BLK, N) \ 254 ((nghttp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) 255 256 /* 257 * nghttp2_ksl_print prints its internal state in stderr. It assumes 258 * that the key is of type int64_t. This function should be used for 259 * the debugging purpose only. 260 */ 261 void nghttp2_ksl_print(nghttp2_ksl *ksl); 262 263 /* 264 * nghttp2_ksl_it_init initializes |it|. 265 */ 266 void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl, 267 nghttp2_ksl_blk *blk, size_t i); 268 269 /* 270 * nghttp2_ksl_it_get returns the data associated to the node which 271 * |it| points to. It is undefined to call this function when 272 * nghttp2_ksl_it_end(it) returns nonzero. 273 */ 274 void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it); 275 276 /* 277 * nghttp2_ksl_it_next advances the iterator by one. It is undefined 278 * if this function is called when nghttp2_ksl_it_end(it) returns 279 * nonzero. 280 */ 281 #define nghttp2_ksl_it_next(IT) \ 282 (++(IT)->i == (IT)->blk->n && (IT)->blk->next \ 283 ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \ 284 : 0) 285 286 /* 287 * nghttp2_ksl_it_prev moves backward the iterator by one. It is 288 * undefined if this function is called when nghttp2_ksl_it_begin(it) 289 * returns nonzero. 290 */ 291 void nghttp2_ksl_it_prev(nghttp2_ksl_it *it); 292 293 /* 294 * nghttp2_ksl_it_end returns nonzero if |it| points to the beyond the 295 * last node. 296 */ 297 #define nghttp2_ksl_it_end(IT) \ 298 ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL) 299 300 /* 301 * nghttp2_ksl_it_begin returns nonzero if |it| points to the first 302 * node. |it| might satisfy both nghttp2_ksl_it_begin(&it) and 303 * nghttp2_ksl_it_end(&it) if the skip list has no node. 304 */ 305 int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it); 306 307 /* 308 * nghttp2_ksl_key returns the key of the node which |it| points to. 309 * It is undefined to call this function when nghttp2_ksl_it_end(it) 310 * returns nonzero. 311 */ 312 #define nghttp2_ksl_it_key(IT) \ 313 ((nghttp2_ksl_key *)nghttp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key) 314 315 #endif /* NGHTTP2_KSL_H */ 316