1 1.11 christos /* $NetBSD: ht.c,v 1.11 2025/01/26 16:25:37 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.7 christos * SPDX-License-Identifier: MPL-2.0 7 1.7 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.6 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.3 christos #include <inttypes.h> 17 1.1 christos #include <string.h> 18 1.1 christos 19 1.11 christos #include <isc/ascii.h> 20 1.1 christos #include <isc/hash.h> 21 1.1 christos #include <isc/ht.h> 22 1.1 christos #include <isc/magic.h> 23 1.1 christos #include <isc/mem.h> 24 1.1 christos #include <isc/result.h> 25 1.5 christos #include <isc/types.h> 26 1.1 christos #include <isc/util.h> 27 1.1 christos 28 1.1 christos typedef struct isc_ht_node isc_ht_node_t; 29 1.1 christos 30 1.5 christos #define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b') 31 1.5 christos #define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC) 32 1.1 christos 33 1.9 christos #define HT_NO_BITS 0 34 1.9 christos #define HT_MIN_BITS 1 35 1.9 christos #define HT_MAX_BITS 32 36 1.9 christos #define HT_OVERCOMMIT 3 37 1.9 christos 38 1.9 christos #define HT_NEXTTABLE(idx) ((idx == 0) ? 1 : 0) 39 1.9 christos #define TRY_NEXTTABLE(idx, ht) (idx == ht->hindex && rehashing_in_progress(ht)) 40 1.9 christos 41 1.9 christos #define GOLDEN_RATIO_32 0x61C88647 42 1.9 christos 43 1.9 christos #define HASHSIZE(bits) (UINT64_C(1) << (bits)) 44 1.9 christos 45 1.1 christos struct isc_ht_node { 46 1.1 christos void *value; 47 1.1 christos isc_ht_node_t *next; 48 1.9 christos uint32_t hashval; 49 1.1 christos size_t keysize; 50 1.9 christos unsigned char key[]; 51 1.1 christos }; 52 1.1 christos 53 1.1 christos struct isc_ht { 54 1.1 christos unsigned int magic; 55 1.1 christos isc_mem_t *mctx; 56 1.9 christos size_t count; 57 1.9 christos bool case_sensitive; 58 1.9 christos size_t size[2]; 59 1.9 christos uint8_t hashbits[2]; 60 1.9 christos isc_ht_node_t **table[2]; 61 1.9 christos uint8_t hindex; 62 1.9 christos uint32_t hiter; /* rehashing iterator */ 63 1.1 christos }; 64 1.1 christos 65 1.1 christos struct isc_ht_iter { 66 1.1 christos isc_ht_t *ht; 67 1.1 christos size_t i; 68 1.9 christos uint8_t hindex; 69 1.1 christos isc_ht_node_t *cur; 70 1.1 christos }; 71 1.1 christos 72 1.9 christos static isc_ht_node_t * 73 1.9 christos isc__ht_find(const isc_ht_t *ht, const unsigned char *key, 74 1.9 christos const uint32_t keysize, const uint32_t hashval, const uint8_t idx); 75 1.9 christos static void 76 1.9 christos isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, 77 1.9 christos const uint32_t hashval, const uint8_t idx, void *value); 78 1.9 christos static isc_result_t 79 1.9 christos isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, 80 1.9 christos const uint32_t hashval, const uint8_t idx); 81 1.9 christos 82 1.9 christos static uint32_t 83 1.9 christos rehash_bits(isc_ht_t *ht, size_t newcount); 84 1.9 christos 85 1.9 christos static void 86 1.9 christos hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits); 87 1.9 christos static void 88 1.9 christos hashtable_free(isc_ht_t *ht, const uint8_t idx); 89 1.9 christos static void 90 1.9 christos hashtable_rehash(isc_ht_t *ht, uint32_t newbits); 91 1.9 christos static void 92 1.9 christos hashtable_rehash_one(isc_ht_t *ht); 93 1.9 christos static void 94 1.9 christos maybe_rehash(isc_ht_t *ht, size_t newcount); 95 1.9 christos 96 1.9 christos static isc_result_t 97 1.9 christos isc__ht_iter_next(isc_ht_iter_t *it); 98 1.9 christos 99 1.9 christos static bool 100 1.9 christos isc__ht_node_match(isc_ht_node_t *node, const uint32_t hashval, 101 1.9 christos const uint8_t *key, uint32_t keysize, bool case_sensitive) { 102 1.11 christos return node->hashval == hashval && node->keysize == keysize && 103 1.11 christos (case_sensitive 104 1.11 christos ? (memcmp(node->key, key, keysize) == 0) 105 1.11 christos : (isc_ascii_lowerequal(node->key, key, keysize))); 106 1.9 christos } 107 1.9 christos 108 1.9 christos static uint32_t 109 1.9 christos hash_32(uint32_t val, unsigned int bits) { 110 1.9 christos REQUIRE(bits <= HT_MAX_BITS); 111 1.9 christos /* High bits are more random. */ 112 1.11 christos return val * GOLDEN_RATIO_32 >> (32 - bits); 113 1.9 christos } 114 1.9 christos 115 1.9 christos static bool 116 1.9 christos rehashing_in_progress(const isc_ht_t *ht) { 117 1.11 christos return ht->table[HT_NEXTTABLE(ht->hindex)] != NULL; 118 1.9 christos } 119 1.9 christos 120 1.9 christos static bool 121 1.9 christos hashtable_is_overcommited(isc_ht_t *ht) { 122 1.11 christos return ht->count >= (ht->size[ht->hindex] * HT_OVERCOMMIT); 123 1.9 christos } 124 1.9 christos 125 1.9 christos static uint32_t 126 1.9 christos rehash_bits(isc_ht_t *ht, size_t newcount) { 127 1.9 christos uint32_t newbits = ht->hashbits[ht->hindex]; 128 1.9 christos 129 1.9 christos while (newcount >= HASHSIZE(newbits) && newbits <= HT_MAX_BITS) { 130 1.9 christos newbits += 1; 131 1.9 christos } 132 1.9 christos 133 1.11 christos return newbits; 134 1.9 christos } 135 1.9 christos 136 1.9 christos /* 137 1.9 christos * Rebuild the hashtable to reduce the load factor 138 1.9 christos */ 139 1.9 christos static void 140 1.9 christos hashtable_rehash(isc_ht_t *ht, uint32_t newbits) { 141 1.9 christos uint8_t oldindex = ht->hindex; 142 1.9 christos uint32_t oldbits = ht->hashbits[oldindex]; 143 1.9 christos uint8_t newindex = HT_NEXTTABLE(oldindex); 144 1.9 christos 145 1.9 christos REQUIRE(ht->hashbits[oldindex] >= HT_MIN_BITS); 146 1.9 christos REQUIRE(ht->hashbits[oldindex] <= HT_MAX_BITS); 147 1.9 christos REQUIRE(ht->table[oldindex] != NULL); 148 1.9 christos 149 1.9 christos REQUIRE(newbits <= HT_MAX_BITS); 150 1.9 christos REQUIRE(ht->hashbits[newindex] == HT_NO_BITS); 151 1.9 christos REQUIRE(ht->table[newindex] == NULL); 152 1.9 christos 153 1.9 christos REQUIRE(newbits > oldbits); 154 1.9 christos 155 1.9 christos hashtable_new(ht, newindex, newbits); 156 1.9 christos 157 1.9 christos ht->hindex = newindex; 158 1.9 christos 159 1.9 christos hashtable_rehash_one(ht); 160 1.9 christos } 161 1.9 christos 162 1.9 christos static void 163 1.9 christos hashtable_rehash_one(isc_ht_t *ht) { 164 1.9 christos isc_ht_node_t **newtable = ht->table[ht->hindex]; 165 1.9 christos uint32_t oldsize = ht->size[HT_NEXTTABLE(ht->hindex)]; 166 1.9 christos isc_ht_node_t **oldtable = ht->table[HT_NEXTTABLE(ht->hindex)]; 167 1.9 christos isc_ht_node_t *node = NULL; 168 1.9 christos isc_ht_node_t *nextnode; 169 1.9 christos 170 1.9 christos /* Find first non-empty node */ 171 1.9 christos while (ht->hiter < oldsize && oldtable[ht->hiter] == NULL) { 172 1.9 christos ht->hiter++; 173 1.9 christos } 174 1.9 christos 175 1.9 christos /* Rehashing complete */ 176 1.9 christos if (ht->hiter == oldsize) { 177 1.9 christos hashtable_free(ht, HT_NEXTTABLE(ht->hindex)); 178 1.9 christos ht->hiter = 0; 179 1.9 christos return; 180 1.9 christos } 181 1.9 christos 182 1.9 christos /* Move the first non-empty node from old hashtable to new hashtable */ 183 1.9 christos for (node = oldtable[ht->hiter]; node != NULL; node = nextnode) { 184 1.9 christos uint32_t hash = hash_32(node->hashval, 185 1.9 christos ht->hashbits[ht->hindex]); 186 1.9 christos nextnode = node->next; 187 1.9 christos node->next = newtable[hash]; 188 1.9 christos newtable[hash] = node; 189 1.9 christos } 190 1.9 christos 191 1.9 christos oldtable[ht->hiter] = NULL; 192 1.9 christos 193 1.9 christos ht->hiter++; 194 1.9 christos } 195 1.9 christos 196 1.9 christos static void 197 1.9 christos maybe_rehash(isc_ht_t *ht, size_t newcount) { 198 1.9 christos uint32_t newbits = rehash_bits(ht, newcount); 199 1.9 christos 200 1.9 christos if (ht->hashbits[ht->hindex] < newbits && newbits <= HT_MAX_BITS) { 201 1.9 christos hashtable_rehash(ht, newbits); 202 1.9 christos } 203 1.9 christos } 204 1.9 christos 205 1.9 christos static void 206 1.9 christos hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits) { 207 1.9 christos REQUIRE(ht->hashbits[idx] == HT_NO_BITS); 208 1.9 christos REQUIRE(ht->table[idx] == NULL); 209 1.9 christos REQUIRE(bits >= HT_MIN_BITS); 210 1.9 christos REQUIRE(bits <= HT_MAX_BITS); 211 1.9 christos 212 1.9 christos ht->hashbits[idx] = bits; 213 1.9 christos ht->size[idx] = HASHSIZE(ht->hashbits[idx]); 214 1.9 christos 215 1.11 christos ht->table[idx] = isc_mem_cget(ht->mctx, ht->size[idx], 216 1.11 christos sizeof(isc_ht_node_t *)); 217 1.9 christos } 218 1.9 christos 219 1.9 christos static void 220 1.9 christos hashtable_free(isc_ht_t *ht, const uint8_t idx) { 221 1.9 christos for (size_t i = 0; i < ht->size[idx]; i++) { 222 1.9 christos isc_ht_node_t *node = ht->table[idx][i]; 223 1.9 christos while (node != NULL) { 224 1.9 christos isc_ht_node_t *next = node->next; 225 1.9 christos ht->count--; 226 1.9 christos isc_mem_put(ht->mctx, node, 227 1.9 christos sizeof(*node) + node->keysize); 228 1.9 christos node = next; 229 1.9 christos } 230 1.9 christos } 231 1.9 christos 232 1.11 christos isc_mem_cput(ht->mctx, ht->table[idx], ht->size[idx], 233 1.11 christos sizeof(isc_ht_node_t *)); 234 1.11 christos 235 1.9 christos ht->hashbits[idx] = HT_NO_BITS; 236 1.9 christos ht->table[idx] = NULL; 237 1.9 christos } 238 1.9 christos 239 1.7 christos void 240 1.9 christos isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits, 241 1.9 christos unsigned int options) { 242 1.1 christos isc_ht_t *ht = NULL; 243 1.9 christos bool case_sensitive = ((options & ISC_HT_CASE_INSENSITIVE) == 0); 244 1.1 christos 245 1.1 christos REQUIRE(htp != NULL && *htp == NULL); 246 1.1 christos REQUIRE(mctx != NULL); 247 1.9 christos REQUIRE(bits >= 1 && bits <= HT_MAX_BITS); 248 1.1 christos 249 1.9 christos ht = isc_mem_get(mctx, sizeof(*ht)); 250 1.9 christos *ht = (isc_ht_t){ 251 1.9 christos .case_sensitive = case_sensitive, 252 1.9 christos }; 253 1.1 christos 254 1.1 christos isc_mem_attach(mctx, &ht->mctx); 255 1.1 christos 256 1.9 christos hashtable_new(ht, 0, bits); 257 1.1 christos 258 1.1 christos ht->magic = ISC_HT_MAGIC; 259 1.1 christos 260 1.1 christos *htp = ht; 261 1.1 christos } 262 1.1 christos 263 1.1 christos void 264 1.1 christos isc_ht_destroy(isc_ht_t **htp) { 265 1.1 christos isc_ht_t *ht; 266 1.1 christos 267 1.1 christos REQUIRE(htp != NULL); 268 1.9 christos REQUIRE(ISC_HT_VALID(*htp)); 269 1.1 christos 270 1.1 christos ht = *htp; 271 1.4 christos *htp = NULL; 272 1.1 christos ht->magic = 0; 273 1.1 christos 274 1.9 christos for (size_t i = 0; i <= 1; i++) { 275 1.9 christos if (ht->table[i] != NULL) { 276 1.9 christos hashtable_free(ht, i); 277 1.1 christos } 278 1.1 christos } 279 1.1 christos 280 1.1 christos INSIST(ht->count == 0); 281 1.1 christos 282 1.9 christos isc_mem_putanddetach(&ht->mctx, ht, sizeof(*ht)); 283 1.9 christos } 284 1.9 christos 285 1.9 christos static void 286 1.9 christos isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, 287 1.9 christos const uint32_t hashval, const uint8_t idx, void *value) { 288 1.9 christos isc_ht_node_t *node; 289 1.9 christos uint32_t hash; 290 1.9 christos 291 1.9 christos hash = hash_32(hashval, ht->hashbits[idx]); 292 1.9 christos 293 1.11 christos node = isc_mem_get(ht->mctx, STRUCT_FLEX_SIZE(node, key, keysize)); 294 1.9 christos *node = (isc_ht_node_t){ 295 1.9 christos .keysize = keysize, 296 1.9 christos .hashval = hashval, 297 1.9 christos .next = ht->table[idx][hash], 298 1.9 christos .value = value, 299 1.9 christos }; 300 1.9 christos 301 1.9 christos memmove(node->key, key, keysize); 302 1.9 christos 303 1.9 christos ht->count++; 304 1.9 christos ht->table[idx][hash] = node; 305 1.1 christos } 306 1.1 christos 307 1.1 christos isc_result_t 308 1.9 christos isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, 309 1.5 christos void *value) { 310 1.9 christos uint32_t hashval; 311 1.1 christos 312 1.1 christos REQUIRE(ISC_HT_VALID(ht)); 313 1.1 christos REQUIRE(key != NULL && keysize > 0); 314 1.1 christos 315 1.9 christos if (rehashing_in_progress(ht)) { 316 1.9 christos /* Rehash in progress */ 317 1.9 christos hashtable_rehash_one(ht); 318 1.9 christos } else if (hashtable_is_overcommited(ht)) { 319 1.9 christos /* Rehash requested */ 320 1.9 christos maybe_rehash(ht, ht->count); 321 1.1 christos } 322 1.1 christos 323 1.9 christos hashval = isc_hash32(key, keysize, ht->case_sensitive); 324 1.1 christos 325 1.9 christos if (isc__ht_find(ht, key, keysize, hashval, ht->hindex) != NULL) { 326 1.11 christos return ISC_R_EXISTS; 327 1.9 christos } 328 1.9 christos 329 1.9 christos isc__ht_add(ht, key, keysize, hashval, ht->hindex, value); 330 1.1 christos 331 1.11 christos return ISC_R_SUCCESS; 332 1.1 christos } 333 1.1 christos 334 1.9 christos static isc_ht_node_t * 335 1.9 christos isc__ht_find(const isc_ht_t *ht, const unsigned char *key, 336 1.9 christos const uint32_t keysize, const uint32_t hashval, 337 1.9 christos const uint8_t idx) { 338 1.9 christos uint32_t hash; 339 1.9 christos uint8_t findex = idx; 340 1.9 christos 341 1.9 christos nexttable: 342 1.9 christos hash = hash_32(hashval, ht->hashbits[findex]); 343 1.9 christos for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL; 344 1.9 christos node = node->next) 345 1.9 christos { 346 1.9 christos if (isc__ht_node_match(node, hashval, key, keysize, 347 1.9 christos ht->case_sensitive)) 348 1.9 christos { 349 1.11 christos return node; 350 1.9 christos } 351 1.9 christos } 352 1.9 christos if (TRY_NEXTTABLE(findex, ht)) { 353 1.9 christos /* 354 1.9 christos * Rehashing in progress, check the other table 355 1.9 christos */ 356 1.9 christos findex = HT_NEXTTABLE(findex); 357 1.9 christos goto nexttable; 358 1.9 christos } 359 1.9 christos 360 1.11 christos return NULL; 361 1.9 christos } 362 1.9 christos 363 1.1 christos isc_result_t 364 1.9 christos isc_ht_find(const isc_ht_t *ht, const unsigned char *key, 365 1.9 christos const uint32_t keysize, void **valuep) { 366 1.9 christos uint32_t hashval; 367 1.1 christos isc_ht_node_t *node; 368 1.1 christos 369 1.1 christos REQUIRE(ISC_HT_VALID(ht)); 370 1.1 christos REQUIRE(key != NULL && keysize > 0); 371 1.3 christos REQUIRE(valuep == NULL || *valuep == NULL); 372 1.1 christos 373 1.9 christos hashval = isc_hash32(key, keysize, ht->case_sensitive); 374 1.9 christos 375 1.9 christos node = isc__ht_find(ht, key, keysize, hashval, ht->hindex); 376 1.9 christos if (node == NULL) { 377 1.11 christos return ISC_R_NOTFOUND; 378 1.1 christos } 379 1.1 christos 380 1.11 christos SET_IF_NOT_NULL(valuep, node->value); 381 1.11 christos return ISC_R_SUCCESS; 382 1.1 christos } 383 1.1 christos 384 1.9 christos static isc_result_t 385 1.9 christos isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, 386 1.9 christos const uint32_t hashval, const uint8_t idx) { 387 1.9 christos isc_ht_node_t *prev = NULL; 388 1.3 christos uint32_t hash; 389 1.1 christos 390 1.9 christos hash = hash_32(hashval, ht->hashbits[idx]); 391 1.1 christos 392 1.9 christos for (isc_ht_node_t *node = ht->table[idx][hash]; node != NULL; 393 1.9 christos prev = node, node = node->next) 394 1.9 christos { 395 1.9 christos if (isc__ht_node_match(node, hashval, key, keysize, 396 1.9 christos ht->case_sensitive)) 397 1.8 christos { 398 1.5 christos if (prev == NULL) { 399 1.9 christos ht->table[idx][hash] = node->next; 400 1.5 christos } else { 401 1.1 christos prev->next = node->next; 402 1.5 christos } 403 1.1 christos isc_mem_put(ht->mctx, node, 404 1.11 christos STRUCT_FLEX_SIZE(node, key, node->keysize)); 405 1.1 christos ht->count--; 406 1.1 christos 407 1.11 christos return ISC_R_SUCCESS; 408 1.1 christos } 409 1.9 christos } 410 1.9 christos 411 1.11 christos return ISC_R_NOTFOUND; 412 1.9 christos } 413 1.9 christos 414 1.9 christos isc_result_t 415 1.9 christos isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize) { 416 1.9 christos uint32_t hashval; 417 1.9 christos uint8_t hindex; 418 1.9 christos isc_result_t result; 419 1.9 christos 420 1.9 christos REQUIRE(ISC_HT_VALID(ht)); 421 1.9 christos REQUIRE(key != NULL && keysize > 0); 422 1.1 christos 423 1.9 christos if (rehashing_in_progress(ht)) { 424 1.9 christos /* Rehash in progress */ 425 1.9 christos hashtable_rehash_one(ht); 426 1.9 christos } 427 1.9 christos 428 1.9 christos hindex = ht->hindex; 429 1.9 christos hashval = isc_hash32(key, keysize, ht->case_sensitive); 430 1.9 christos nexttable: 431 1.9 christos result = isc__ht_delete(ht, key, keysize, hashval, hindex); 432 1.9 christos 433 1.9 christos if (result == ISC_R_NOTFOUND && TRY_NEXTTABLE(hindex, ht)) { 434 1.9 christos /* 435 1.9 christos * Rehashing in progress, check the other table 436 1.9 christos */ 437 1.9 christos hindex = HT_NEXTTABLE(hindex); 438 1.9 christos goto nexttable; 439 1.1 christos } 440 1.9 christos 441 1.11 christos return result; 442 1.1 christos } 443 1.1 christos 444 1.7 christos void 445 1.1 christos isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { 446 1.1 christos isc_ht_iter_t *it; 447 1.1 christos 448 1.1 christos REQUIRE(ISC_HT_VALID(ht)); 449 1.1 christos REQUIRE(itp != NULL && *itp == NULL); 450 1.1 christos 451 1.1 christos it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t)); 452 1.9 christos *it = (isc_ht_iter_t){ 453 1.9 christos .ht = ht, 454 1.9 christos .hindex = ht->hindex, 455 1.9 christos }; 456 1.1 christos 457 1.1 christos *itp = it; 458 1.1 christos } 459 1.1 christos 460 1.1 christos void 461 1.1 christos isc_ht_iter_destroy(isc_ht_iter_t **itp) { 462 1.1 christos isc_ht_iter_t *it; 463 1.1 christos isc_ht_t *ht; 464 1.1 christos 465 1.1 christos REQUIRE(itp != NULL && *itp != NULL); 466 1.1 christos 467 1.1 christos it = *itp; 468 1.5 christos *itp = NULL; 469 1.1 christos ht = it->ht; 470 1.9 christos isc_mem_put(ht->mctx, it, sizeof(*it)); 471 1.1 christos } 472 1.1 christos 473 1.1 christos isc_result_t 474 1.1 christos isc_ht_iter_first(isc_ht_iter_t *it) { 475 1.9 christos isc_ht_t *ht; 476 1.9 christos 477 1.1 christos REQUIRE(it != NULL); 478 1.1 christos 479 1.9 christos ht = it->ht; 480 1.9 christos 481 1.9 christos it->hindex = ht->hindex; 482 1.1 christos it->i = 0; 483 1.9 christos 484 1.11 christos return isc__ht_iter_next(it); 485 1.9 christos } 486 1.9 christos 487 1.9 christos static isc_result_t 488 1.9 christos isc__ht_iter_next(isc_ht_iter_t *it) { 489 1.9 christos isc_ht_t *ht = it->ht; 490 1.9 christos 491 1.9 christos while (it->i < ht->size[it->hindex] && 492 1.9 christos ht->table[it->hindex][it->i] == NULL) 493 1.9 christos { 494 1.1 christos it->i++; 495 1.5 christos } 496 1.1 christos 497 1.9 christos if (it->i < ht->size[it->hindex]) { 498 1.9 christos it->cur = ht->table[it->hindex][it->i]; 499 1.9 christos 500 1.11 christos return ISC_R_SUCCESS; 501 1.5 christos } 502 1.1 christos 503 1.9 christos if (TRY_NEXTTABLE(it->hindex, ht)) { 504 1.9 christos it->hindex = HT_NEXTTABLE(it->hindex); 505 1.9 christos it->i = 0; 506 1.11 christos return isc__ht_iter_next(it); 507 1.9 christos } 508 1.1 christos 509 1.11 christos return ISC_R_NOMORE; 510 1.1 christos } 511 1.1 christos 512 1.1 christos isc_result_t 513 1.1 christos isc_ht_iter_next(isc_ht_iter_t *it) { 514 1.1 christos REQUIRE(it != NULL); 515 1.1 christos REQUIRE(it->cur != NULL); 516 1.1 christos 517 1.1 christos it->cur = it->cur->next; 518 1.9 christos 519 1.9 christos if (it->cur != NULL) { 520 1.11 christos return ISC_R_SUCCESS; 521 1.1 christos } 522 1.1 christos 523 1.9 christos it->i++; 524 1.9 christos 525 1.11 christos return isc__ht_iter_next(it); 526 1.1 christos } 527 1.1 christos 528 1.1 christos isc_result_t 529 1.1 christos isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) { 530 1.1 christos isc_result_t result = ISC_R_SUCCESS; 531 1.9 christos isc_ht_node_t *dnode = NULL; 532 1.9 christos uint8_t dindex; 533 1.1 christos isc_ht_t *ht; 534 1.9 christos isc_result_t dresult; 535 1.9 christos 536 1.1 christos REQUIRE(it != NULL); 537 1.1 christos REQUIRE(it->cur != NULL); 538 1.9 christos 539 1.1 christos ht = it->ht; 540 1.9 christos dnode = it->cur; 541 1.9 christos dindex = it->hindex; 542 1.1 christos 543 1.9 christos result = isc_ht_iter_next(it); 544 1.1 christos 545 1.9 christos dresult = isc__ht_delete(ht, dnode->key, dnode->keysize, dnode->hashval, 546 1.9 christos dindex); 547 1.9 christos INSIST(dresult == ISC_R_SUCCESS); 548 1.1 christos 549 1.11 christos return result; 550 1.1 christos } 551 1.1 christos 552 1.1 christos void 553 1.1 christos isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) { 554 1.1 christos REQUIRE(it != NULL); 555 1.1 christos REQUIRE(it->cur != NULL); 556 1.3 christos REQUIRE(valuep != NULL && *valuep == NULL); 557 1.3 christos 558 1.1 christos *valuep = it->cur->value; 559 1.1 christos } 560 1.1 christos 561 1.1 christos void 562 1.5 christos isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, 563 1.5 christos size_t *keysize) { 564 1.1 christos REQUIRE(it != NULL); 565 1.1 christos REQUIRE(it->cur != NULL); 566 1.3 christos REQUIRE(key != NULL && *key == NULL); 567 1.3 christos 568 1.1 christos *key = it->cur->key; 569 1.1 christos *keysize = it->cur->keysize; 570 1.1 christos } 571 1.1 christos 572 1.9 christos size_t 573 1.9 christos isc_ht_count(const isc_ht_t *ht) { 574 1.1 christos REQUIRE(ISC_HT_VALID(ht)); 575 1.1 christos 576 1.11 christos return ht->count; 577 1.1 christos } 578