1 /* $NetBSD: ht.c,v 1.5 2020/05/24 19:46:26 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 #include <inttypes.h> 15 #include <string.h> 16 17 #include <isc/hash.h> 18 #include <isc/ht.h> 19 #include <isc/magic.h> 20 #include <isc/mem.h> 21 #include <isc/result.h> 22 #include <isc/types.h> 23 #include <isc/util.h> 24 25 typedef struct isc_ht_node isc_ht_node_t; 26 27 #define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b') 28 #define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC) 29 30 struct isc_ht_node { 31 void *value; 32 isc_ht_node_t *next; 33 size_t keysize; 34 unsigned char key[FLEXIBLE_ARRAY_MEMBER]; 35 }; 36 37 struct isc_ht { 38 unsigned int magic; 39 isc_mem_t *mctx; 40 size_t size; 41 size_t mask; 42 unsigned int count; 43 isc_ht_node_t **table; 44 }; 45 46 struct isc_ht_iter { 47 isc_ht_t *ht; 48 size_t i; 49 isc_ht_node_t *cur; 50 }; 51 52 isc_result_t 53 isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { 54 isc_ht_t *ht = NULL; 55 size_t i; 56 57 REQUIRE(htp != NULL && *htp == NULL); 58 REQUIRE(mctx != NULL); 59 REQUIRE(bits >= 1 && bits <= (sizeof(size_t) * 8 - 1)); 60 61 ht = isc_mem_get(mctx, sizeof(struct isc_ht)); 62 63 ht->mctx = NULL; 64 isc_mem_attach(mctx, &ht->mctx); 65 66 ht->size = ((size_t)1 << bits); 67 ht->mask = ((size_t)1 << bits) - 1; 68 ht->count = 0; 69 70 ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t *)); 71 72 for (i = 0; i < ht->size; i++) { 73 ht->table[i] = NULL; 74 } 75 76 ht->magic = ISC_HT_MAGIC; 77 78 *htp = ht; 79 return (ISC_R_SUCCESS); 80 } 81 82 void 83 isc_ht_destroy(isc_ht_t **htp) { 84 isc_ht_t *ht; 85 size_t i; 86 87 REQUIRE(htp != NULL); 88 89 ht = *htp; 90 *htp = NULL; 91 92 REQUIRE(ISC_HT_VALID(ht)); 93 94 ht->magic = 0; 95 96 for (i = 0; i < ht->size; i++) { 97 isc_ht_node_t *node = ht->table[i]; 98 while (node != NULL) { 99 isc_ht_node_t *next = node->next; 100 ht->count--; 101 isc_mem_put(ht->mctx, node, 102 offsetof(isc_ht_node_t, key) + 103 node->keysize); 104 node = next; 105 } 106 } 107 108 INSIST(ht->count == 0); 109 110 isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t *)); 111 isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht)); 112 } 113 114 isc_result_t 115 isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize, 116 void *value) { 117 isc_ht_node_t *node; 118 uint32_t hash; 119 120 REQUIRE(ISC_HT_VALID(ht)); 121 REQUIRE(key != NULL && keysize > 0); 122 123 hash = isc_hash_function(key, keysize, true); 124 node = ht->table[hash & ht->mask]; 125 while (node != NULL) { 126 if (keysize == node->keysize && 127 memcmp(key, node->key, keysize) == 0) { 128 return (ISC_R_EXISTS); 129 } 130 node = node->next; 131 } 132 133 node = isc_mem_get(ht->mctx, offsetof(isc_ht_node_t, key) + keysize); 134 135 memmove(node->key, key, keysize); 136 node->keysize = keysize; 137 node->next = ht->table[hash & ht->mask]; 138 node->value = value; 139 140 ht->count++; 141 ht->table[hash & ht->mask] = node; 142 return (ISC_R_SUCCESS); 143 } 144 145 isc_result_t 146 isc_ht_find(const isc_ht_t *ht, const unsigned char *key, uint32_t keysize, 147 void **valuep) { 148 isc_ht_node_t *node; 149 uint32_t hash; 150 151 REQUIRE(ISC_HT_VALID(ht)); 152 REQUIRE(key != NULL && keysize > 0); 153 REQUIRE(valuep == NULL || *valuep == NULL); 154 155 hash = isc_hash_function(key, keysize, true); 156 node = ht->table[hash & ht->mask]; 157 while (node != NULL) { 158 if (keysize == node->keysize && 159 memcmp(key, node->key, keysize) == 0) { 160 if (valuep != NULL) { 161 *valuep = node->value; 162 } 163 return (ISC_R_SUCCESS); 164 } 165 node = node->next; 166 } 167 168 return (ISC_R_NOTFOUND); 169 } 170 171 isc_result_t 172 isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) { 173 isc_ht_node_t *node, *prev; 174 uint32_t hash; 175 176 REQUIRE(ISC_HT_VALID(ht)); 177 REQUIRE(key != NULL && keysize > 0); 178 179 prev = NULL; 180 hash = isc_hash_function(key, keysize, true); 181 node = ht->table[hash & ht->mask]; 182 while (node != NULL) { 183 if (keysize == node->keysize && 184 memcmp(key, node->key, keysize) == 0) { 185 if (prev == NULL) { 186 ht->table[hash & ht->mask] = node->next; 187 } else { 188 prev->next = node->next; 189 } 190 isc_mem_put(ht->mctx, node, 191 offsetof(isc_ht_node_t, key) + 192 node->keysize); 193 ht->count--; 194 195 return (ISC_R_SUCCESS); 196 } 197 198 prev = node; 199 node = node->next; 200 } 201 return (ISC_R_NOTFOUND); 202 } 203 204 isc_result_t 205 isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { 206 isc_ht_iter_t *it; 207 208 REQUIRE(ISC_HT_VALID(ht)); 209 REQUIRE(itp != NULL && *itp == NULL); 210 211 it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t)); 212 213 it->ht = ht; 214 it->i = 0; 215 it->cur = NULL; 216 217 *itp = it; 218 219 return (ISC_R_SUCCESS); 220 } 221 222 void 223 isc_ht_iter_destroy(isc_ht_iter_t **itp) { 224 isc_ht_iter_t *it; 225 isc_ht_t *ht; 226 227 REQUIRE(itp != NULL && *itp != NULL); 228 229 it = *itp; 230 *itp = NULL; 231 ht = it->ht; 232 isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t)); 233 } 234 235 isc_result_t 236 isc_ht_iter_first(isc_ht_iter_t *it) { 237 REQUIRE(it != NULL); 238 239 it->i = 0; 240 while (it->i < it->ht->size && it->ht->table[it->i] == NULL) { 241 it->i++; 242 } 243 244 if (it->i == it->ht->size) { 245 return (ISC_R_NOMORE); 246 } 247 248 it->cur = it->ht->table[it->i]; 249 250 return (ISC_R_SUCCESS); 251 } 252 253 isc_result_t 254 isc_ht_iter_next(isc_ht_iter_t *it) { 255 REQUIRE(it != NULL); 256 REQUIRE(it->cur != NULL); 257 258 it->cur = it->cur->next; 259 if (it->cur == NULL) { 260 do { 261 it->i++; 262 } while (it->i < it->ht->size && it->ht->table[it->i] == NULL); 263 if (it->i >= it->ht->size) { 264 return (ISC_R_NOMORE); 265 } 266 it->cur = it->ht->table[it->i]; 267 } 268 269 return (ISC_R_SUCCESS); 270 } 271 272 isc_result_t 273 isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) { 274 isc_result_t result = ISC_R_SUCCESS; 275 isc_ht_node_t *to_delete = NULL; 276 isc_ht_node_t *prev = NULL; 277 isc_ht_node_t *node = NULL; 278 uint32_t hash; 279 isc_ht_t *ht; 280 REQUIRE(it != NULL); 281 REQUIRE(it->cur != NULL); 282 to_delete = it->cur; 283 ht = it->ht; 284 285 it->cur = it->cur->next; 286 if (it->cur == NULL) { 287 do { 288 it->i++; 289 } while (it->i < ht->size && ht->table[it->i] == NULL); 290 if (it->i >= ht->size) { 291 result = ISC_R_NOMORE; 292 } else { 293 it->cur = ht->table[it->i]; 294 } 295 } 296 297 hash = isc_hash_function(to_delete->key, to_delete->keysize, true); 298 node = ht->table[hash & ht->mask]; 299 while (node != to_delete) { 300 prev = node; 301 node = node->next; 302 INSIST(node != NULL); 303 } 304 305 if (prev == NULL) { 306 ht->table[hash & ht->mask] = node->next; 307 } else { 308 prev->next = node->next; 309 } 310 isc_mem_put(ht->mctx, node, 311 offsetof(isc_ht_node_t, key) + node->keysize); 312 ht->count--; 313 314 return (result); 315 } 316 317 void 318 isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) { 319 REQUIRE(it != NULL); 320 REQUIRE(it->cur != NULL); 321 REQUIRE(valuep != NULL && *valuep == NULL); 322 323 *valuep = it->cur->value; 324 } 325 326 void 327 isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, 328 size_t *keysize) { 329 REQUIRE(it != NULL); 330 REQUIRE(it->cur != NULL); 331 REQUIRE(key != NULL && *key == NULL); 332 333 *key = it->cur->key; 334 *keysize = it->cur->keysize; 335 } 336 337 unsigned int 338 isc_ht_count(isc_ht_t *ht) { 339 REQUIRE(ISC_HT_VALID(ht)); 340 341 return (ht->count); 342 } 343