hmap.c (5677B)
1#include "hmap.h" 2 3#include <errno.h> 4#include <stdbool.h> 5#include <string.h> 6 7static inline size_t 8hmap_key_bucket(const struct hmap *map, struct hmap_key key) 9{ 10 return map->hash(key) % map->bucketcnt; 11} 12 13int 14hmap_init(struct hmap *map, size_t size, hmap_hash_func hasher, 15 hmap_keycmp_func keycmp, const struct allocator *allocator) 16{ 17 int rc; 18 19 LIBHMAP_ABORT_ON_ARGS(!size || !hasher || !keycmp || !allocator); 20 21 map->allocator = allocator; 22 map->keycmp = keycmp; 23 map->bucketcnt = size; 24 map->hash = hasher; 25 map->buckets = map->allocator->alloc(map->allocator, 26 sizeof(void *) * size, &rc); 27 if (!map->buckets) return -rc; 28 memset(map->buckets, 0, size * sizeof(void *)); 29 30 return 0; 31} 32 33int 34hmap_deinit(struct hmap *map) 35{ 36 LIBHMAP_ABORT_ON_ARGS(!map); 37 38 hmap_clear(map); 39 40 return map->allocator->free(map->allocator, map->buckets); 41} 42 43struct hmap * 44hmap_alloc(size_t size, hmap_hash_func hasher, 45 hmap_keycmp_func keycmp, const struct allocator *allocator, int *_rc) 46{ 47 struct hmap *map; 48 int *rc, stub; 49 50 LIBHMAP_ABORT_ON_ARGS(!allocator); 51 52 rc = _rc ? _rc : &stub; 53 54 map = allocator->alloc(allocator, sizeof(struct hmap), rc); 55 if (!map && _rc) *rc = -*rc; 56 if (!map) return NULL; 57 58 *rc = hmap_init(map, size, hasher, keycmp, allocator); 59 if (*rc) { 60 allocator->free(allocator, map); 61 return NULL; 62 } 63 64 return map; 65} 66 67int 68hmap_free(struct hmap *map) 69{ 70 const struct allocator *allocator; 71 int rc; 72 73 LIBHMAP_ABORT_ON_ARGS(!map); 74 75 allocator = map->allocator; 76 rc = hmap_deinit(map); 77 if (rc) return rc; 78 79 rc = allocator->free(allocator, map); 80 if (rc) return -rc; 81 82 return 0; 83} 84 85int 86hmap_copy(const struct hmap *dst, const struct hmap *src) 87{ 88 struct hmap_iter iter; 89 int rc; 90 91 LIBHMAP_ABORT_ON_ARGS(!dst || !src); 92 93 for (HMAP_ITER(src, iter)) { 94 rc = hmap_set(dst, iter.link->key, iter.link->value); 95 if (rc) return rc; 96 } 97 98 return 0; 99} 100 101void 102hmap_swap(struct hmap *m1, struct hmap *m2) 103{ 104 struct hmap tmp; 105 106 LIBHMAP_ABORT_ON_ARGS(!m1 || !m2); 107 108 memcpy(&tmp, m1, sizeof(struct hmap)); 109 memcpy(m1, m2, sizeof(struct hmap)); 110 memcpy(m2, &tmp, sizeof(struct hmap)); 111} 112 113void 114hmap_clear(const struct hmap *map) 115{ 116 struct hmap_iter iter; 117 struct hmap_link *prev; 118 size_t i; 119 120 LIBHMAP_ABORT_ON_ARGS(!map); 121 122 prev = NULL; 123 for (HMAP_ITER(map, iter)) { 124 map->allocator->free(map->allocator, prev); 125 prev = iter.link; 126 } 127 map->allocator->free(map->allocator, prev); 128 129 for (i = 0; i < map->bucketcnt; i++) 130 map->buckets[i] = NULL; 131} 132 133struct hmap_link ** 134hmap_link_get(const struct hmap *map, struct hmap_key key) 135{ 136 struct hmap_link **iter, *link; 137 138 LIBHMAP_ABORT_ON_ARGS(!map); 139 140 iter = &map->buckets[hmap_key_bucket(map, key)]; 141 while (*iter != NULL) { 142 link = *iter; 143 if (map->keycmp(link->key, key)) 144 return iter; 145 iter = &(*iter)->next; 146 } 147 148 return NULL; 149} 150 151struct hmap_link ** 152hmap_link_pos(const struct hmap *map, struct hmap_key key) 153{ 154 struct hmap_link **iter, *link; 155 156 LIBHMAP_ABORT_ON_ARGS(!map); 157 158 iter = &map->buckets[hmap_key_bucket(map, key)]; 159 while (*iter != NULL) { 160 link = *iter; 161 if (map->keycmp(link->key, key)) 162 return iter; 163 iter = &(*iter)->next; 164 } 165 166 return iter; 167} 168 169struct hmap_link * 170hmap_link_pop(const struct hmap *map, struct hmap_link **link) 171{ 172 struct hmap_link *tmp; 173 174 LIBHMAP_ABORT_ON_ARGS(!map || !link); 175 176 tmp = *link; 177 *link = (*link)->next; 178 179 return tmp; 180} 181 182struct hmap_link * 183hmap_link_alloc(const struct hmap *map, 184 struct hmap_key key, struct hmap_val value, int *rc) 185{ 186 struct hmap_link *link; 187 188 LIBHMAP_ABORT_ON_ARGS(!map); 189 190 link = map->allocator->alloc(map->allocator, 191 sizeof(struct hmap_link), rc); 192 if (!link && rc) *rc = -*rc; 193 if (!link) return NULL; 194 195 link->key = key; 196 link->value = value; 197 link->next = NULL; 198 199 return link; 200} 201 202struct hmap_link * 203hmap_get(const struct hmap *map, struct hmap_key key) 204{ 205 struct hmap_link **iter; 206 207 LIBHMAP_ABORT_ON_ARGS(!map); 208 209 iter = hmap_link_get(map, key); 210 211 return iter ? *iter : NULL; 212} 213 214int 215hmap_set(const struct hmap *map, struct hmap_key key, struct hmap_val value) 216{ 217 struct hmap_link **iter; 218 219 LIBHMAP_ABORT_ON_ARGS(!map); 220 221 iter = hmap_link_pos(map, key); 222 if (!*iter) return HMAP_KEY_MISSING; 223 224 (*iter)->value = value; 225 226 return 0; 227} 228 229int 230hmap_rm(const struct hmap *map, struct hmap_key key) 231{ 232 struct hmap_link *link, **linkp; 233 int rc; 234 235 LIBHMAP_ABORT_ON_ARGS(!map); 236 237 linkp = hmap_link_get(map, key); 238 if (!linkp) return HMAP_KEY_MISSING; 239 link = hmap_link_pop(map, linkp); 240 241 rc = map->allocator->free(map->allocator, link); 242 if (rc) return -rc; 243 244 return 0; 245} 246 247int 248hmap_add(const struct hmap *map, struct hmap_key key, struct hmap_val value) 249{ 250 struct hmap_link **iter; 251 int rc; 252 253 LIBHMAP_ABORT_ON_ARGS(!map); 254 255 iter = hmap_link_pos(map, key); 256 if (*iter) return HMAP_KEY_EXISTS; 257 258 *iter = hmap_link_alloc(map, key, value, &rc); 259 if (!*iter) return rc; 260 261 return 0; 262} 263 264void 265hmap_iter_init(struct hmap_iter *iter) 266{ 267 LIBHMAP_ABORT_ON_ARGS(!iter); 268 269 iter->bucket = 0; 270 iter->link = NULL; 271} 272 273bool 274hmap_iter_next(const struct hmap *map, struct hmap_iter *iter) 275{ 276 size_t i; 277 278 LIBHMAP_ABORT_ON_ARGS(!map || !iter); 279 280 if (iter->link && iter->link->next) { 281 iter->link = iter->link->next; 282 return true; 283 } 284 285 i = iter->bucket + (iter->link ? 1 : 0); 286 for (; i < map->bucketcnt; i++) { 287 if (map->buckets[i]) { 288 iter->bucket = i; 289 iter->link = map->buckets[i]; 290 return true; 291 } 292 } 293 294 iter->link = NULL; 295 296 return false; 297} 298 299uint32_t 300hmap_str_hash(struct hmap_key key) 301{ 302 const char *c; 303 uint32_t hash; 304 305 LIBHMAP_ABORT_ON_ARGS(!key.p); 306 307 hash = 5381; 308 for (c = key.p; *c; c++) 309 hash = 33 * hash + (uint8_t) *c; 310 311 return hash; 312} 313 314bool 315hmap_str_keycmp(struct hmap_key k1, struct hmap_key k2) 316{ 317 LIBHMAP_ABORT_ON_ARGS(!k1.p || !k2.p); 318 319 return !strcmp(k1.p, k2.p); 320}