ares_slist.c (11239B)
1 /* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 #include "ares_private.h" 27 #include "ares_slist.h" 28 29 /* SkipList implementation */ 30 31 #define ARES__SLIST_START_LEVELS 4 32 33 struct ares_slist { 34 ares_rand_state *rand_state; 35 unsigned char rand_data[8]; 36 size_t rand_bits; 37 38 ares_slist_node_t **head; 39 size_t levels; 40 ares_slist_node_t *tail; 41 42 ares_slist_cmp_t cmp; 43 ares_slist_destructor_t destruct; 44 size_t cnt; 45 }; 46 47 struct ares_slist_node { 48 void *data; 49 ares_slist_node_t **prev; 50 ares_slist_node_t **next; 51 size_t levels; 52 ares_slist_t *parent; 53 }; 54 55 ares_slist_t *ares_slist_create(ares_rand_state *rand_state, 56 ares_slist_cmp_t cmp, 57 ares_slist_destructor_t destruct) 58 { 59 ares_slist_t *list; 60 61 if (rand_state == NULL || cmp == NULL) { 62 return NULL; 63 } 64 65 list = ares_malloc_zero(sizeof(*list)); 66 67 if (list == NULL) { 68 return NULL; 69 } 70 71 list->rand_state = rand_state; 72 list->cmp = cmp; 73 list->destruct = destruct; 74 75 list->levels = ARES__SLIST_START_LEVELS; 76 list->head = ares_malloc_zero(sizeof(*list->head) * list->levels); 77 if (list->head == NULL) { 78 ares_free(list); 79 return NULL; 80 } 81 82 return list; 83 } 84 85 static ares_bool_t ares_slist_coin_flip(ares_slist_t *list) 86 { 87 size_t total_bits = sizeof(list->rand_data) * 8; 88 size_t bit; 89 90 /* Refill random data used for coin flips. We pull this in 8 byte chunks. 91 * ares_rand_bytes() has some built-in caching of its own so we don't need 92 * to be excessive in caching ourselves. Prefer to require less memory per 93 * skiplist */ 94 if (list->rand_bits == 0) { 95 ares_rand_bytes(list->rand_state, list->rand_data, sizeof(list->rand_data)); 96 list->rand_bits = total_bits; 97 } 98 99 bit = total_bits - list->rand_bits; 100 list->rand_bits--; 101 102 return (list->rand_data[bit / 8] & (1 << (bit % 8))) ? ARES_TRUE : ARES_FALSE; 103 } 104 105 void ares_slist_replace_destructor(ares_slist_t *list, 106 ares_slist_destructor_t destruct) 107 { 108 if (list == NULL) { 109 return; 110 } 111 112 list->destruct = destruct; 113 } 114 115 static size_t ares_slist_max_level(const ares_slist_t *list) 116 { 117 size_t max_level = 0; 118 119 if (list->cnt + 1 <= (1 << ARES__SLIST_START_LEVELS)) { 120 max_level = ARES__SLIST_START_LEVELS; 121 } else { 122 max_level = ares_log2(ares_round_up_pow2(list->cnt + 1)); 123 } 124 125 if (list->levels > max_level) { 126 max_level = list->levels; 127 } 128 129 return max_level; 130 } 131 132 static size_t ares_slist_calc_level(ares_slist_t *list) 133 { 134 size_t max_level = ares_slist_max_level(list); 135 size_t level; 136 137 for (level = 1; ares_slist_coin_flip(list) && level < max_level; level++) 138 ; 139 140 return level; 141 } 142 143 static void ares_slist_node_push(ares_slist_t *list, ares_slist_node_t *node) 144 { 145 size_t i; 146 ares_slist_node_t *left = NULL; 147 148 /* Scan from highest level in the slist, even if we're not using that number 149 * of levels for this entry as this is what makes it O(log n) */ 150 for (i = list->levels; i-- > 0;) { 151 /* set left if left is NULL and the current node value is greater than the 152 * head at this level */ 153 if (left == NULL && list->head[i] != NULL && 154 list->cmp(node->data, list->head[i]->data) > 0) { 155 left = list->head[i]; 156 } 157 158 if (left != NULL) { 159 /* scan forward to find our insertion point */ 160 while (left->next[i] != NULL && 161 list->cmp(node->data, left->next[i]->data) > 0) { 162 left = left->next[i]; 163 } 164 } 165 166 /* search only as we didn't randomly select this number of levels */ 167 if (i >= node->levels) { 168 continue; 169 } 170 171 if (left == NULL) { 172 /* head insertion */ 173 node->next[i] = list->head[i]; 174 node->prev[i] = NULL; 175 list->head[i] = node; 176 } else { 177 /* Chain */ 178 node->next[i] = left->next[i]; 179 node->prev[i] = left; 180 left->next[i] = node; 181 } 182 183 if (node->next[i] != NULL) { 184 /* chain prev */ 185 node->next[i]->prev[i] = node; 186 } else { 187 if (i == 0) { 188 /* update tail */ 189 list->tail = node; 190 } 191 } 192 } 193 } 194 195 ares_slist_node_t *ares_slist_insert(ares_slist_t *list, void *val) 196 { 197 ares_slist_node_t *node = NULL; 198 199 if (list == NULL || val == NULL) { 200 return NULL; 201 } 202 203 node = ares_malloc_zero(sizeof(*node)); 204 205 if (node == NULL) { 206 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ 207 } 208 209 node->data = val; 210 node->parent = list; 211 212 /* Randomly determine the number of levels we want to use */ 213 node->levels = ares_slist_calc_level(list); 214 215 /* Allocate array of next and prev nodes for linking each level */ 216 node->next = ares_malloc_zero(sizeof(*node->next) * node->levels); 217 if (node->next == NULL) { 218 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ 219 } 220 221 node->prev = ares_malloc_zero(sizeof(*node->prev) * node->levels); 222 if (node->prev == NULL) { 223 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ 224 } 225 226 /* If the number of levels is greater than we currently support in the slist, 227 * increase the count */ 228 if (list->levels < node->levels) { 229 void *ptr = 230 ares_realloc_zero(list->head, sizeof(*list->head) * list->levels, 231 sizeof(*list->head) * node->levels); 232 if (ptr == NULL) { 233 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ 234 } 235 236 list->head = ptr; 237 list->levels = node->levels; 238 } 239 240 ares_slist_node_push(list, node); 241 242 list->cnt++; 243 244 return node; 245 246 /* LCOV_EXCL_START: OutOfMemory */ 247 fail: 248 if (node) { 249 ares_free(node->prev); 250 ares_free(node->next); 251 ares_free(node); 252 } 253 return NULL; 254 /* LCOV_EXCL_STOP */ 255 } 256 257 static void ares_slist_node_pop(ares_slist_node_t *node) 258 { 259 ares_slist_t *list = node->parent; 260 size_t i; 261 262 /* relink each node at each level */ 263 for (i = node->levels; i-- > 0;) { 264 if (node->next[i] == NULL) { 265 if (i == 0) { 266 list->tail = node->prev[0]; 267 } 268 } else { 269 node->next[i]->prev[i] = node->prev[i]; 270 } 271 272 if (node->prev[i] == NULL) { 273 list->head[i] = node->next[i]; 274 } else { 275 node->prev[i]->next[i] = node->next[i]; 276 } 277 } 278 279 memset(node->next, 0, sizeof(*node->next) * node->levels); 280 memset(node->prev, 0, sizeof(*node->prev) * node->levels); 281 } 282 283 void *ares_slist_node_claim(ares_slist_node_t *node) 284 { 285 ares_slist_t *list; 286 void *val; 287 288 if (node == NULL) { 289 return NULL; 290 } 291 292 list = node->parent; 293 val = node->data; 294 295 ares_slist_node_pop(node); 296 297 ares_free(node->next); 298 ares_free(node->prev); 299 ares_free(node); 300 301 list->cnt--; 302 303 return val; 304 } 305 306 void ares_slist_node_reinsert(ares_slist_node_t *node) 307 { 308 ares_slist_t *list; 309 310 if (node == NULL) { 311 return; 312 } 313 314 list = node->parent; 315 316 ares_slist_node_pop(node); 317 ares_slist_node_push(list, node); 318 } 319 320 ares_slist_node_t *ares_slist_node_find(const ares_slist_t *list, 321 const void *val) 322 { 323 size_t i; 324 ares_slist_node_t *node = NULL; 325 int rv = -1; 326 327 if (list == NULL || val == NULL) { 328 return NULL; 329 } 330 331 /* Scan nodes starting at the highest level. For each level scan forward 332 * until the value is between the prior and next node, or if equal quit 333 * as we found a match */ 334 for (i = list->levels; i-- > 0;) { 335 if (node == NULL) { 336 node = list->head[i]; 337 } 338 339 if (node == NULL) { 340 continue; 341 } 342 343 do { 344 rv = list->cmp(val, node->data); 345 346 if (rv < 0) { 347 /* back off, our value is greater than current node reference */ 348 node = node->prev[i]; 349 } else if (rv > 0) { 350 /* move forward and try again. if it goes past, it will loop again and 351 * go to previous entry */ 352 node = node->next[i]; 353 } 354 355 /* rv == 0 will terminate loop */ 356 357 } while (node != NULL && rv > 0); 358 359 /* Found a match, no need to continue */ 360 if (rv == 0) { 361 break; 362 } 363 } 364 365 /* no match */ 366 if (rv != 0) { 367 return NULL; 368 } 369 370 /* The list may have multiple entries that match. They're guaranteed to be 371 * in order, but we're not guaranteed to have selected the _first_ matching 372 * node. Lets scan backwards to find the first match */ 373 while (node->prev[0] != NULL && list->cmp(node->prev[0]->data, val) == 0) { 374 node = node->prev[0]; 375 } 376 377 return node; 378 } 379 380 ares_slist_node_t *ares_slist_node_first(const ares_slist_t *list) 381 { 382 if (list == NULL) { 383 return NULL; 384 } 385 386 return list->head[0]; 387 } 388 389 ares_slist_node_t *ares_slist_node_last(const ares_slist_t *list) 390 { 391 if (list == NULL) { 392 return NULL; 393 } 394 return list->tail; 395 } 396 397 ares_slist_node_t *ares_slist_node_next(const ares_slist_node_t *node) 398 { 399 if (node == NULL) { 400 return NULL; 401 } 402 return node->next[0]; 403 } 404 405 ares_slist_node_t *ares_slist_node_prev(const ares_slist_node_t *node) 406 { 407 if (node == NULL) { 408 return NULL; 409 } 410 return node->prev[0]; 411 } 412 413 void *ares_slist_node_val(ares_slist_node_t *node) 414 { 415 if (node == NULL) { 416 return NULL; 417 } 418 419 return node->data; 420 } 421 422 size_t ares_slist_len(const ares_slist_t *list) 423 { 424 if (list == NULL) { 425 return 0; 426 } 427 return list->cnt; 428 } 429 430 ares_slist_t *ares_slist_node_parent(ares_slist_node_t *node) 431 { 432 if (node == NULL) { 433 return NULL; 434 } 435 return node->parent; 436 } 437 438 void *ares_slist_first_val(const ares_slist_t *list) 439 { 440 return ares_slist_node_val(ares_slist_node_first(list)); 441 } 442 443 void *ares_slist_last_val(const ares_slist_t *list) 444 { 445 return ares_slist_node_val(ares_slist_node_last(list)); 446 } 447 448 void ares_slist_node_destroy(ares_slist_node_t *node) 449 { 450 ares_slist_destructor_t destruct; 451 void *val; 452 453 if (node == NULL) { 454 return; 455 } 456 457 destruct = node->parent->destruct; 458 val = ares_slist_node_claim(node); 459 460 if (val != NULL && destruct != NULL) { 461 destruct(val); 462 } 463 } 464 465 void ares_slist_destroy(ares_slist_t *list) 466 { 467 ares_slist_node_t *node; 468 469 if (list == NULL) { 470 return; 471 } 472 473 while ((node = ares_slist_node_first(list)) != NULL) { 474 ares_slist_node_destroy(node); 475 } 476 477 ares_free(list->head); 478 ares_free(list); 479 }