1 /* 2 * nghttp3 3 * 4 * Copyright (c) 2019 nghttp3 contributors 5 * Copyright (c) 2018 ngtcp2 contributors 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 #ifndef NGHTTP3_KSL_H 27 #define NGHTTP3_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 <nghttp3/nghttp3.h> 36 37 #include "nghttp3_objalloc.h" 38 39 /* 40 * Skip List using single key instead of range. 41 */ 42 43 #define NGHTTP3_KSL_DEGR 16 44 /* NGHTTP3_KSL_MAX_NBLK is the maximum number of nodes which a single 45 block can contain. */ 46 #define NGHTTP3_KSL_MAX_NBLK (2 * NGHTTP3_KSL_DEGR - 1) 47 /* NGHTTP3_KSL_MIN_NBLK is the minimum number of nodes which a single 48 block other than root must contains. */ 49 #define NGHTTP3_KSL_MIN_NBLK (NGHTTP3_KSL_DEGR - 1) 50 51 /* 52 * nghttp3_ksl_key represents key in nghttp3_ksl. 53 */ 54 typedef void nghttp3_ksl_key; 55 56 typedef struct nghttp3_ksl_node nghttp3_ksl_node; 57 58 typedef struct nghttp3_ksl_blk nghttp3_ksl_blk; 59 60 /* 61 * nghttp3_ksl_node is a node which contains either nghttp3_ksl_blk or 62 * opaque data. If a node is an internal node, it contains 63 * nghttp3_ksl_blk. Otherwise, it has data. The key is stored at the 64 * location starting at key. 65 */ 66 struct nghttp3_ksl_node { 67 union { 68 nghttp3_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 nghttp3_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 * nghttp3_ksl_blk contains nghttp3_ksl_node objects. 83 */ 84 struct nghttp3_ksl_blk { 85 union { 86 struct { 87 /* next points to the next block if leaf field is nonzero. */ 88 nghttp3_ksl_blk *next; 89 /* prev points to the previous block if leaf field is 90 nonzero. */ 91 nghttp3_ksl_blk *prev; 92 /* n is the number of nodes this object contains in nodes. */ 93 uint32_t n; 94 /* leaf is nonzero if this block contains leaf nodes. */ 95 uint32_t leaf; 96 union { 97 uint64_t align; 98 /* nodes is a buffer to contain NGHTTP3_KSL_MAX_NBLK 99 nghttp3_ksl_node objects. Because nghttp3_ksl_node object 100 is allocated along with the additional variable length key 101 storage, the size of buffer is unknown until 102 nghttp3_ksl_init is called. */ 103 uint8_t nodes[1]; 104 }; 105 }; 106 107 nghttp3_opl_entry oplent; 108 }; 109 }; 110 111 nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent); 112 113 /* 114 * nghttp3_ksl_compar is a function type which returns nonzero if key 115 * |lhs| should be placed before |rhs|. It returns 0 otherwise. 116 */ 117 typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs, 118 const nghttp3_ksl_key *rhs); 119 120 typedef struct nghttp3_ksl nghttp3_ksl; 121 122 typedef struct nghttp3_ksl_it nghttp3_ksl_it; 123 124 /* 125 * nghttp3_ksl_it is a forward iterator to iterate nodes. 126 */ 127 struct nghttp3_ksl_it { 128 const nghttp3_ksl *ksl; 129 nghttp3_ksl_blk *blk; 130 size_t i; 131 }; 132 133 /* 134 * nghttp3_ksl is a deterministic paged skip list. 135 */ 136 struct nghttp3_ksl { 137 nghttp3_objalloc blkalloc; 138 /* head points to the root block. */ 139 nghttp3_ksl_blk *head; 140 /* front points to the first leaf block. */ 141 nghttp3_ksl_blk *front; 142 /* back points to the last leaf block. */ 143 nghttp3_ksl_blk *back; 144 nghttp3_ksl_compar compar; 145 size_t n; 146 /* keylen is the size of key */ 147 size_t keylen; 148 /* nodelen is the actual size of nghttp3_ksl_node including key 149 storage. */ 150 size_t nodelen; 151 }; 152 153 /* 154 * nghttp3_ksl_init initializes |ksl|. |compar| specifies compare 155 * function. |keylen| is the length of key. 156 */ 157 void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, 158 size_t keylen, const nghttp3_mem *mem); 159 160 /* 161 * nghttp3_ksl_free frees resources allocated for |ksl|. If |ksl| is 162 * NULL, this function does nothing. It does not free the memory 163 * region pointed by |ksl| itself. 164 */ 165 void nghttp3_ksl_free(nghttp3_ksl *ksl); 166 167 /* 168 * nghttp3_ksl_insert inserts |key| with its associated |data|. On 169 * successful insertion, the iterator points to the inserted node is 170 * stored in |*it|. 171 * 172 * This function returns 0 if it succeeds, or one of the following 173 * negative error codes: 174 * 175 * NGHTTP3_ERR_NOMEM 176 * Out of memory. 177 * NGHTTP3_ERR_INVALID_ARGUMENT 178 * |key| already exists. 179 */ 180 int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it, 181 const nghttp3_ksl_key *key, void *data); 182 183 /* 184 * nghttp3_ksl_remove removes the |key| from |ksl|. 185 * 186 * This function assigns the iterator to |*it|, which points to the 187 * node which is located at the right next of the removed node if |it| 188 * is not NULL. If |key| is not found, no deletion takes place and 189 * the return value of nghttp3_ksl_end(ksl) is assigned to |*it|. 190 * 191 * This function returns 0 if it succeeds, or one of the following 192 * negative error codes: 193 * 194 * NGHTTP3_ERR_INVALID_ARGUMENT 195 * |key| does not exist. 196 */ 197 int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it, 198 const nghttp3_ksl_key *key); 199 200 /* 201 * nghttp3_ksl_remove_hint removes the |key| from |ksl|. |hint| must 202 * point to the same node denoted by |key|. |hint| is used to remove 203 * a node efficiently in some cases. Other than that, it behaves 204 * exactly like nghttp3_ksl_remove. |it| and |hint| can point to the 205 * same object. 206 */ 207 int nghttp3_ksl_remove_hint(nghttp3_ksl *ksl, nghttp3_ksl_it *it, 208 const nghttp3_ksl_it *hint, 209 const nghttp3_ksl_key *key); 210 211 /* 212 * nghttp3_ksl_lower_bound returns the iterator which points to the 213 * first node which has the key which is equal to |key| or the last 214 * node which satisfies !compar(&node->key, key). If there is no such 215 * node, it returns the iterator which satisfies nghttp3_ksl_it_end(it) 216 * != 0. 217 */ 218 nghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl, 219 const nghttp3_ksl_key *key); 220 221 /* 222 * nghttp3_ksl_lower_bound_compar works like nghttp3_ksl_lower_bound, 223 * but it takes custom function |compar| to do lower bound search. 224 */ 225 nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl, 226 const nghttp3_ksl_key *key, 227 nghttp3_ksl_compar compar); 228 229 /* 230 * nghttp3_ksl_update_key replaces the key of nodes which has |old_key| 231 * with |new_key|. |new_key| must be strictly greater than the 232 * previous node and strictly smaller than the next node. 233 */ 234 void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key, 235 const nghttp3_ksl_key *new_key); 236 237 /* 238 * nghttp3_ksl_begin returns the iterator which points to the first 239 * node. If there is no node in |ksl|, it returns the iterator which 240 * satisfies nghttp3_ksl_it_end(it) != 0. 241 */ 242 nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl); 243 244 /* 245 * nghttp3_ksl_end returns the iterator which points to the node 246 * following the last node. The returned object satisfies 247 * nghttp3_ksl_it_end(). If there is no node in |ksl|, it returns the 248 * iterator which satisfies nghttp3_ksl_it_begin(it) != 0. 249 */ 250 nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl); 251 252 /* 253 * nghttp3_ksl_len returns the number of elements stored in |ksl|. 254 */ 255 size_t nghttp3_ksl_len(nghttp3_ksl *ksl); 256 257 /* 258 * nghttp3_ksl_clear removes all elements stored in |ksl|. 259 */ 260 void nghttp3_ksl_clear(nghttp3_ksl *ksl); 261 262 /* 263 * nghttp3_ksl_nth_node returns the |n|th node under |blk|. 264 */ 265 #define nghttp3_ksl_nth_node(KSL, BLK, N) \ 266 ((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) 267 268 /* 269 * nghttp3_ksl_print prints its internal state in stderr. It assumes 270 * that the key is of type int64_t. This function should be used for 271 * the debugging purpose only. 272 */ 273 void nghttp3_ksl_print(nghttp3_ksl *ksl); 274 275 /* 276 * nghttp3_ksl_it_init initializes |it|. 277 */ 278 void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl, 279 nghttp3_ksl_blk *blk, size_t i); 280 281 /* 282 * nghttp3_ksl_it_get returns the data associated to the node which 283 * |it| points to. It is undefined to call this function when 284 * nghttp3_ksl_it_end(it) returns nonzero. 285 */ 286 #define nghttp3_ksl_it_get(IT) \ 287 nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data 288 289 /* 290 * nghttp3_ksl_it_next advances the iterator by one. It is undefined 291 * if this function is called when nghttp3_ksl_it_end(it) returns 292 * nonzero. 293 */ 294 #define nghttp3_ksl_it_next(IT) \ 295 (++(IT)->i == (IT)->blk->n && (IT)->blk->next \ 296 ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \ 297 : 0) 298 299 /* 300 * nghttp3_ksl_it_prev moves backward the iterator by one. It is 301 * undefined if this function is called when nghttp3_ksl_it_begin(it) 302 * returns nonzero. 303 */ 304 void nghttp3_ksl_it_prev(nghttp3_ksl_it *it); 305 306 /* 307 * nghttp3_ksl_it_end returns nonzero if |it| points to the beyond the 308 * last node. 309 */ 310 #define nghttp3_ksl_it_end(IT) \ 311 ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL) 312 313 /* 314 * nghttp3_ksl_it_begin returns nonzero if |it| points to the first 315 * node. |it| might satisfy both nghttp3_ksl_it_begin(&it) and 316 * nghttp3_ksl_it_end(&it) if the skip list has no node. 317 */ 318 int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it); 319 320 /* 321 * nghttp3_ksl_key returns the key of the node which |it| points to. 322 * It is undefined to call this function when nghttp3_ksl_it_end(it) 323 * returns nonzero. 324 */ 325 #define nghttp3_ksl_it_key(IT) \ 326 ((nghttp3_ksl_key *)nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key) 327 328 /* 329 * nghttp3_ksl_range_compar is an implementation of 330 * nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to 331 * nghttp3_range object and the function returns nonzero if (const 332 * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range 333 * *)(rhs->ptr)->begin. 334 */ 335 int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs, 336 const nghttp3_ksl_key *rhs); 337 338 /* 339 * nghttp3_ksl_range_exclusive_compar is an implementation of 340 * nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to 341 * nghttp3_range object and the function returns nonzero if (const 342 * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range 343 * *)(rhs->ptr)->begin and the 2 ranges do not intersect. 344 */ 345 int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs, 346 const nghttp3_ksl_key *rhs); 347 348 #endif /* NGHTTP3_KSL_H */ 349