Commit 9e428935f7874cea1c1d4c5367d040aa38eb8626
- Diff rendering mode:
- inline
- side by side
genhash.c
(93 / 47)
|   | |||
| 18 | 18 | 1610612741 | |
| 19 | 19 | }; | |
| 20 | 20 | ||
| 21 | static inline void* | ||
| 22 | dup_key(genhash_t *h, const void *key, size_t klen) | ||
| 23 | { | ||
| 24 | if (h->ops.dupKey != NULL) { | ||
| 25 | return h->ops.dupKey(key, klen); | ||
| 26 | } else { | ||
| 27 | return (void*)key; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | static inline void* | ||
| 32 | dup_value(genhash_t *h, const void *value, size_t vlen) | ||
| 33 | { | ||
| 34 | if (h->ops.dupValue != NULL) { | ||
| 35 | return h->ops.dupValue(value, vlen); | ||
| 36 | } else { | ||
| 37 | return (void*)value; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void | ||
| 42 | free_key(genhash_t *h, void *key) | ||
| 43 | { | ||
| 44 | if (h->ops.freeKey != NULL) { | ||
| 45 | h->ops.freeKey(key); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void | ||
| 50 | free_value(genhash_t *h, void *value) | ||
| 51 | { | ||
| 52 | if (h->ops.freeValue != NULL) { | ||
| 53 | h->ops.freeValue(value); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 21 | 57 | static int | |
| 22 | 58 | estimate_table_size(int est) | |
| 23 | 59 | { | |
| … | … | ||
| 78 | 78 | ||
| 79 | 79 | assert(ops.hashfunc != NULL); | |
| 80 | 80 | assert(ops.hasheq != NULL); | |
| 81 | assert(ops.dupKey != NULL); | ||
| 82 | assert(ops.dupValue != NULL); | ||
| 83 | assert(ops.freeKey != NULL); | ||
| 84 | assert(ops.freeValue != NULL); | ||
| 81 | assert((ops.dupKey != NULL && ops.freeKey != NULL) || ops.freeKey == NULL); | ||
| 82 | assert((ops.dupValue != NULL && ops.freeValue != NULL) || ops.freeValue == NULL); | ||
| 85 | 83 | ||
| 86 | 84 | size=estimate_table_size(est); | |
| 87 | 85 | rv=calloc(1, sizeof(genhash_t) | |
| … | … | ||
| 101 | 101 | } | |
| 102 | 102 | ||
| 103 | 103 | void | |
| 104 | genhash_store(genhash_t *h, const void* k, const void* v) | ||
| 104 | genhash_store(genhash_t *h, const void* k, size_t klen, | ||
| 105 | const void* v, size_t vlen) | ||
| 105 | 106 | { | |
| 106 | 107 | int n=0; | |
| 107 | 108 | struct genhash_entry_t *p; | |
| 108 | 109 | ||
| 109 | 110 | assert(h != NULL); | |
| 110 | 111 | ||
| 111 | n=h->ops.hashfunc(k) % h->size; | ||
| 112 | n=h->ops.hashfunc(k, klen) % h->size; | ||
| 112 | 113 | assert(n >= 0); | |
| 113 | 114 | assert(n < h->size); | |
| 114 | 115 | ||
| 115 | 116 | p=calloc(1, sizeof(struct genhash_entry_t)); | |
| 116 | 117 | assert(p); | |
| 117 | 118 | ||
| 118 | p->key=h->ops.dupKey(k); | ||
| 119 | p->value=h->ops.dupValue(v); | ||
| 119 | p->key=dup_key(h, k, klen); | ||
| 120 | p->nkey = klen; | ||
| 121 | p->value=dup_value(h, v, vlen); | ||
| 122 | p->nvalue = vlen; | ||
| 120 | 123 | ||
| 121 | 124 | p->next=h->buckets[n]; | |
| 122 | 125 | h->buckets[n]=p; | |
| 123 | 126 | } | |
| 124 | 127 | ||
| 125 | 128 | static struct genhash_entry_t * | |
| 126 | genhash_find_entry(genhash_t *h, const void* k) | ||
| 129 | genhash_find_entry(genhash_t *h, const void* k, size_t klen) | ||
| 127 | 130 | { | |
| 128 | 131 | int n=0; | |
| 129 | 132 | struct genhash_entry_t *p; | |
| 130 | 133 | ||
| 131 | 134 | assert(h != NULL); | |
| 132 | n=h->ops.hashfunc(k) % h->size; | ||
| 135 | n=h->ops.hashfunc(k, klen) % h->size; | ||
| 133 | 136 | assert(n >= 0); | |
| 134 | 137 | assert(n < h->size); | |
| 135 | 138 | ||
| 136 | 139 | p=h->buckets[n]; | |
| 137 | for(p=h->buckets[n]; p && !h->ops.hasheq(k, p->key); p=p->next); | ||
| 140 | for(p=h->buckets[n]; p && !h->ops.hasheq(k, klen, p->key, p->nkey); p=p->next); | ||
| 138 | 141 | return p; | |
| 139 | 142 | } | |
| 140 | 143 | ||
| 141 | 144 | void* | |
| 142 | genhash_find(genhash_t *h, const void* k) | ||
| 145 | genhash_find(genhash_t *h, const void* k, size_t klen) | ||
| 143 | 146 | { | |
| 144 | 147 | struct genhash_entry_t *p; | |
| 145 | 148 | void *rv=NULL; | |
| 146 | 149 | ||
| 147 | p=genhash_find_entry(h, k); | ||
| 150 | p=genhash_find_entry(h, k, klen); | ||
| 148 | 151 | ||
| 149 | 152 | if(p) { | |
| 150 | 153 | rv=p->value; | |
| … | … | ||
| 156 | 156 | } | |
| 157 | 157 | ||
| 158 | 158 | enum update_type | |
| 159 | genhash_update(genhash_t* h, const void* k, const void* v) | ||
| 159 | genhash_update(genhash_t* h, const void* k, size_t klen, | ||
| 160 | const void* v, size_t vlen) | ||
| 160 | 161 | { | |
| 161 | 162 | struct genhash_entry_t *p; | |
| 162 | 163 | enum update_type rv=0; | |
| 163 | 164 | ||
| 164 | p=genhash_find_entry(h, k); | ||
| 165 | p=genhash_find_entry(h, k, klen); | ||
| 165 | 166 | ||
| 166 | 167 | if(p) { | |
| 167 | h->ops.freeValue(p->value); | ||
| 168 | p->value=h->ops.dupValue(v); | ||
| 168 | free_value(h, p->value); | ||
| 169 | p->value=dup_value(h, v, vlen); | ||
| 169 | 170 | rv=MODIFICATION; | |
| 170 | 171 | } else { | |
| 171 | genhash_store(h, k, v); | ||
| 172 | genhash_store(h, k, klen, v, vlen); | ||
| 172 | 173 | rv=NEW; | |
| 173 | 174 | } | |
| 174 | 175 | ||
| … | … | ||
| 177 | 177 | } | |
| 178 | 178 | ||
| 179 | 179 | enum update_type | |
| 180 | genhash_fun_update(genhash_t* h, const void* k, | ||
| 181 | void *(*upd)(const void *, const void *), | ||
| 180 | genhash_fun_update(genhash_t* h, const void* k, size_t klen, | ||
| 181 | void *(*upd)(const void *, const void *, size_t *, void *), | ||
| 182 | 182 | void (*fr)(void*), | |
| 183 | const void *def) | ||
| 183 | void *arg, | ||
| 184 | const void *def, size_t deflen) | ||
| 184 | 185 | { | |
| 185 | 186 | struct genhash_entry_t *p; | |
| 186 | 187 | enum update_type rv=0; | |
| 188 | size_t newSize = 0; | ||
| 187 | 189 | ||
| 188 | p=genhash_find_entry(h, k); | ||
| 190 | p=genhash_find_entry(h, k, klen); | ||
| 189 | 191 | ||
| 190 | 192 | if(p) { | |
| 191 | void *newValue=upd(k, p->value); | ||
| 192 | h->ops.freeValue(p->value); | ||
| 193 | p->value=h->ops.dupValue(newValue); | ||
| 193 | void *newValue=upd(k, p->value, &newSize, arg); | ||
| 194 | free_value(h, p->value); | ||
| 195 | p->value=dup_value(h, newValue, newSize); | ||
| 194 | 196 | fr(newValue); | |
| 195 | 197 | rv=MODIFICATION; | |
| 196 | 198 | } else { | |
| 197 | void *newValue=upd(k, def); | ||
| 198 | genhash_store(h, k, newValue); | ||
| 199 | void *newValue=upd(k, def, &newSize, arg); | ||
| 200 | genhash_store(h, k, klen, newValue, newSize); | ||
| 199 | 201 | fr(newValue); | |
| 200 | 202 | rv=NEW; | |
| 201 | 203 | } | |
| … | … | ||
| 209 | 209 | free_item(genhash_t *h, struct genhash_entry_t *i) | |
| 210 | 210 | { | |
| 211 | 211 | assert(i); | |
| 212 | h->ops.freeKey(i->key); | ||
| 213 | h->ops.freeValue(i->value); | ||
| 212 | free_key(h, i->key); | ||
| 213 | free_value(h, i->value); | ||
| 214 | 214 | free(i); | |
| 215 | 215 | } | |
| 216 | 216 | ||
| 217 | 217 | int | |
| 218 | genhash_delete(genhash_t* h, const void* k) | ||
| 218 | genhash_delete(genhash_t* h, const void* k, size_t klen) | ||
| 219 | 219 | { | |
| 220 | 220 | struct genhash_entry_t *deleteme=NULL; | |
| 221 | 221 | int n=0; | |
| 222 | 222 | int rv=0; | |
| 223 | 223 | ||
| 224 | 224 | assert(h != NULL); | |
| 225 | n=h->ops.hashfunc(k) % h->size; | ||
| 225 | n=h->ops.hashfunc(k, klen) % h->size; | ||
| 226 | 226 | assert(n >= 0); | |
| 227 | 227 | assert(n < h->size); | |
| 228 | 228 | ||
| 229 | 229 | if(h->buckets[n] != NULL) { | |
| 230 | 230 | /* Special case the first one */ | |
| 231 | if(h->ops.hasheq(h->buckets[n]->key, k)) { | ||
| 231 | if(h->ops.hasheq(h->buckets[n]->key, h->buckets[n]->nkey, k, klen)) { | ||
| 232 | 232 | deleteme=h->buckets[n]; | |
| 233 | 233 | h->buckets[n]=deleteme->next; | |
| 234 | 234 | } else { | |
| 235 | 235 | struct genhash_entry_t *p=NULL; | |
| 236 | 236 | for(p=h->buckets[n]; deleteme==NULL && p->next != NULL; p=p->next) { | |
| 237 | if(h->ops.hasheq(p->next->key, k)) { | ||
| 237 | if(h->ops.hasheq(p->next->key, p->next->nkey, k, klen)) { | ||
| 238 | 238 | deleteme=p->next; | |
| 239 | 239 | p->next=deleteme->next; | |
| 240 | 240 | } | |
| … | … | ||
| 250 | 250 | } | |
| 251 | 251 | ||
| 252 | 252 | int | |
| 253 | genhash_delete_all(genhash_t* h, const void* k) | ||
| 253 | genhash_delete_all(genhash_t* h, const void* k, size_t klen) | ||
| 254 | 254 | { | |
| 255 | 255 | int rv=0; | |
| 256 | while(genhash_delete(h, k) == 1) { | ||
| 256 | while(genhash_delete(h, k, klen) == 1) { | ||
| 257 | 257 | rv++; | |
| 258 | 258 | } | |
| 259 | 259 | return rv; | |
| … | … | ||
| 261 | 261 | ||
| 262 | 262 | void | |
| 263 | 263 | genhash_iter(genhash_t* h, | |
| 264 | void (*iterfunc)(const void* key, const void* val, void *arg), void *arg) | ||
| 264 | void (*iterfunc)(const void* key, size_t nkey, | ||
| 265 | const void* val, size_t nval, | ||
| 266 | void *arg), void *arg) | ||
| 265 | 267 | { | |
| 266 | 268 | int i=0; | |
| 267 | 269 | struct genhash_entry_t *p=NULL; | |
| … | … | ||
| 271 | 271 | ||
| 272 | 272 | for(i=0; i<h->size; i++) { | |
| 273 | 273 | for(p=h->buckets[i]; p!=NULL; p=p->next) { | |
| 274 | iterfunc(p->key, p->value, arg); | ||
| 274 | iterfunc(p->key, p->nkey, p->value, p->nvalue, arg); | ||
| 275 | 275 | } | |
| 276 | 276 | } | |
| 277 | 277 | } | |
| … | … | ||
| 295 | 295 | } | |
| 296 | 296 | ||
| 297 | 297 | static void | |
| 298 | count_entries(const void *key, const void *val, void *arg) | ||
| 298 | count_entries(const void *key, size_t klen, | ||
| 299 | const void *val, size_t vlen, void *arg) | ||
| 299 | 300 | { | |
| 300 | 301 | int *count=(int *)arg; | |
| 301 | 302 | (*count)++; | |
| … | … | ||
| 311 | 311 | } | |
| 312 | 312 | ||
| 313 | 313 | int | |
| 314 | genhash_size_for_key(genhash_t* h, const void* k) | ||
| 314 | genhash_size_for_key(genhash_t* h, const void* k, size_t klen) | ||
| 315 | 315 | { | |
| 316 | 316 | int rv=0; | |
| 317 | 317 | assert(h != NULL); | |
| 318 | genhash_iter_key(h, k, count_entries, &rv); | ||
| 318 | genhash_iter_key(h, k, klen, count_entries, &rv); | ||
| 319 | 319 | return rv; | |
| 320 | 320 | } | |
| 321 | 321 | ||
| 322 | 322 | void | |
| 323 | genhash_iter_key(genhash_t* h, const void* key, | ||
| 324 | void (*iterfunc)(const void* key, const void* val, void *arg), void *arg) | ||
| 323 | genhash_iter_key(genhash_t* h, const void* key, size_t klen, | ||
| 324 | void (*iterfunc)(const void* key, size_t klen, | ||
| 325 | const void* val, size_t vlen, | ||
| 326 | void *arg), void *arg) | ||
| 325 | 327 | { | |
| 326 | 328 | int n=0; | |
| 327 | 329 | struct genhash_entry_t *p=NULL; | |
| 328 | 330 | ||
| 329 | 331 | assert(h != NULL); | |
| 330 | n=h->ops.hashfunc(key) % h->size; | ||
| 332 | n=h->ops.hashfunc(key, klen) % h->size; | ||
| 331 | 333 | assert(n >= 0); | |
| 332 | 334 | assert(n < h->size); | |
| 333 | 335 | ||
| 334 | 336 | for(p=h->buckets[n]; p!=NULL; p=p->next) { | |
| 335 | if(h->ops.hasheq(key, p->key)) { | ||
| 336 | iterfunc(p->key, p->value, arg); | ||
| 337 | if(h->ops.hasheq(key, klen, p->key, p->nkey)) { | ||
| 338 | iterfunc(p->key, p->nkey, p->value, p->nvalue, arg); | ||
| 337 | 339 | } | |
| 338 | 340 | } | |
| 339 | 341 | } | |
| 340 | 342 | ||
| 341 | 343 | int | |
| 342 | genhash_string_hash(const void* p) | ||
| 344 | genhash_string_hash(const void* p, size_t nkey) | ||
| 343 | 345 | { | |
| 344 | 346 | int rv=5381; | |
| 345 | 347 | int i=0; | |
| 346 | 348 | char *str=(char *)p; | |
| 347 | 349 | ||
| 348 | for(i=0; str[i] != 0x00; i++) { | ||
| 350 | for(i=0; i < nkey; i++) { | ||
| 351 | assert(str[i]); | ||
| 349 | 352 | rv = ((rv << 5) + rv) ^ str[i]; | |
| 350 | 353 | } | |
| 351 | 354 |
genhash.h
(25 / 17)
|   | |||
| 35 | 35 | /** | |
| 36 | 36 | * Function to compute a hash for the given value. | |
| 37 | 37 | */ | |
| 38 | int (*hashfunc)(const void *); | ||
| 38 | int (*hashfunc)(const void *, size_t); | ||
| 39 | 39 | /** | |
| 40 | 40 | * Function that returns true if the given keys are equal. | |
| 41 | 41 | */ | |
| 42 | int (*hasheq)(const void *, const void *); | ||
| 42 | int (*hasheq)(const void *, size_t, const void *, size_t); | ||
| 43 | 43 | /** | |
| 44 | 44 | * Function to duplicate a key for storage. | |
| 45 | 45 | */ | |
| 46 | void* (*dupKey)(const void *); | ||
| 46 | void* (*dupKey)(const void *, size_t); | ||
| 47 | 47 | /** | |
| 48 | 48 | * Function to duplicate a value for storage. | |
| 49 | 49 | */ | |
| 50 | void* (*dupValue)(const void *); | ||
| 50 | void* (*dupValue)(const void *, size_t); | ||
| 51 | 51 | /** | |
| 52 | 52 | * Function to free a key. | |
| 53 | 53 | */ | |
| … | … | ||
| 95 | 95 | * @param k the key | |
| 96 | 96 | * @param v the value | |
| 97 | 97 | */ | |
| 98 | void genhash_store(genhash_t *h, const void *k, const void *v); | ||
| 98 | void genhash_store(genhash_t *h, const void *k, size_t klen, | ||
| 99 | const void *v, size_t vlen); | ||
| 99 | 100 | ||
| 100 | 101 | /** | |
| 101 | 102 | * Get the most recent value stored for the given key. | |
| … | … | ||
| 106 | 106 | * | |
| 107 | 107 | * @return the value, or NULL if one cannot be found | |
| 108 | 108 | */ | |
| 109 | void* genhash_find(genhash_t *h, const void *k); | ||
| 109 | void* genhash_find(genhash_t *h, const void *k, size_t klen); | ||
| 110 | 110 | ||
| 111 | 111 | /** | |
| 112 | 112 | * Delete the most recent value stored for a key. | |
| … | … | ||
| 116 | 116 | * | |
| 117 | 117 | * @return the number of items deleted | |
| 118 | 118 | */ | |
| 119 | int genhash_delete(genhash_t *h, const void *k); | ||
| 119 | int genhash_delete(genhash_t *h, const void *k, size_t klen); | ||
| 120 | 120 | ||
| 121 | 121 | /** | |
| 122 | 122 | * Delete all mappings of a given key. | |
| … | … | ||
| 126 | 126 | * | |
| 127 | 127 | * @return the number of items deleted | |
| 128 | 128 | */ | |
| 129 | int genhash_delete_all(genhash_t *h, const void *k); | ||
| 129 | int genhash_delete_all(genhash_t *h, const void *k, size_t klen); | ||
| 130 | 130 | ||
| 131 | 131 | /** | |
| 132 | 132 | * Create or update an item in-place. | |
| … | … | ||
| 138 | 138 | * @return an indicator of whether this created a new item or updated | |
| 139 | 139 | * an existing one | |
| 140 | 140 | */ | |
| 141 | enum update_type genhash_update(genhash_t *h, const void *k, const void *v); | ||
| 141 | enum update_type genhash_update(genhash_t *h, const void *k, size_t klen, | ||
| 142 | const void *v, size_t vlen); | ||
| 142 | 143 | ||
| 143 | 144 | /** | |
| 144 | 145 | * Create or update an item in-place with a function. | |
| … | … | ||
| 155 | 155 | * @return an indicator of whether this created a new item or updated | |
| 156 | 156 | * an existing one | |
| 157 | 157 | */ | |
| 158 | enum update_type genhash_fun_update(genhash_t *h, const void *key, | ||
| 159 | void *(*upd)(const void *k, const void *oldv), | ||
| 158 | enum update_type genhash_fun_update(genhash_t *h, const void *key, size_t klen, | ||
| 159 | void *(*upd)(const void *k, const void *oldv, | ||
| 160 | size_t *ns, void *a), | ||
| 160 | 161 | void (*fr)(void*), | |
| 161 | const void *def); | ||
| 162 | void *arg, | ||
| 163 | const void *def, size_t deflen); | ||
| 162 | 164 | ||
| 163 | 165 | /** | |
| 164 | 166 | * Iterate all keys and values in a hash table. | |
| … | … | ||
| 170 | 170 | * @param arg an argument to be passed to the iterfunc on each iteration | |
| 171 | 171 | */ | |
| 172 | 172 | void genhash_iter(genhash_t *h, | |
| 173 | void (*iterfunc)(const void* key, const void* val, void *arg), | ||
| 173 | void (*iterfunc)(const void* key, size_t nkey, | ||
| 174 | const void* val, size_t nval, | ||
| 175 | void *arg), | ||
| 174 | 176 | void *arg); | |
| 175 | 177 | ||
| 176 | 178 | /** | |
| … | … | ||
| 183 | 183 | * @param iterfunc a function that will be called once for every k/v pair | |
| 184 | 184 | * @param arg an argument to be passed to the iterfunc on each iteration | |
| 185 | 185 | */ | |
| 186 | void genhash_iter_key(genhash_t *h, const void* key, | ||
| 187 | void (*iterfunc)(const void* key, const void* val, void *arg), | ||
| 186 | void genhash_iter_key(genhash_t *h, const void* key, size_t nkey, | ||
| 187 | void (*iterfunc)(const void* key, size_t inkey, | ||
| 188 | const void* val, size_t inval, | ||
| 189 | void *arg), | ||
| 188 | 190 | void *arg); | |
| 189 | 191 | ||
| 190 | 192 | /** | |
| … | … | ||
| 216 | 216 | * | |
| 217 | 217 | * @return the number of entries keyed with the given key | |
| 218 | 218 | */ | |
| 219 | int genhash_size_for_key(genhash_t *h, const void *k); | ||
| 219 | int genhash_size_for_key(genhash_t *h, const void *k, size_t nkey); | ||
| 220 | 220 | ||
| 221 | 221 | /** | |
| 222 | 222 | * Convenient hash function for strings. | |
| … | … | ||
| 225 | 225 | * | |
| 226 | 226 | * @return a hash value for this string. | |
| 227 | 227 | */ | |
| 228 | int genhash_string_hash(const void *k); | ||
| 228 | int genhash_string_hash(const void *k, size_t nkey); | ||
| 229 | 229 | ||
| 230 | 230 | /** | |
| 231 | 231 | * @} |
genhash_int.h
(4 / 0)
|   | |||
| 4 | 4 | struct genhash_entry_t { | |
| 5 | 5 | /** The key for this entry */ | |
| 6 | 6 | void *key; | |
| 7 | /** Size of the key */ | ||
| 8 | size_t nkey; | ||
| 7 | 9 | /** The value for this entry */ | |
| 8 | 10 | void *value; | |
| 11 | /** Size of the value */ | ||
| 12 | size_t nvalue; | ||
| 9 | 13 | /** Pointer to the next entry */ | |
| 10 | 14 | struct genhash_entry_t *next; | |
| 11 | 15 | }; |
Comments
Add a new comment:
Login or create an account to post a comment
Add your comment
Please log in to comment

