1 /* 2 * libkmod - interface to kernel module operations 3 * 4 * Copyright (C) 2011-2013 ProFUSION embedded systems 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <errno.h> 21 #include <inttypes.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include <shared/hash.h> 26 #include <shared/util.h> 27 28 struct hash_entry { 29 const char *key; 30 const void *value; 31 }; 32 33 struct hash_bucket { 34 struct hash_entry *entries; 35 unsigned int used; 36 unsigned int total; 37 }; 38 39 struct hash { 40 unsigned int count; 41 unsigned int step; 42 unsigned int n_buckets; 43 void (*free_value)(void *value); 44 struct hash_bucket buckets[]; 45 }; 46 47 struct hash *hash_new(unsigned int n_buckets, 48 void (*free_value)(void *value)) 49 { 50 struct hash *hash; 51 52 n_buckets = ALIGN_POWER2(n_buckets); 53 hash = calloc(1, sizeof(struct hash) + 54 n_buckets * sizeof(struct hash_bucket)); 55 if (hash == NULL) 56 return NULL; 57 hash->n_buckets = n_buckets; 58 hash->free_value = free_value; 59 hash->step = n_buckets / 32; 60 if (hash->step == 0) 61 hash->step = 4; 62 else if (hash->step > 64) 63 hash->step = 64; 64 return hash; 65 } 66 67 void hash_free(struct hash *hash) 68 { 69 struct hash_bucket *bucket, *bucket_end; 70 71 if (hash == NULL) 72 return; 73 74 bucket = hash->buckets; 75 bucket_end = bucket + hash->n_buckets; 76 for (; bucket < bucket_end; bucket++) { 77 if (hash->free_value) { 78 struct hash_entry *entry, *entry_end; 79 entry = bucket->entries; 80 entry_end = entry + bucket->used; 81 for (; entry < entry_end; entry++) 82 hash->free_value((void *)entry->value); 83 } 84 free(bucket->entries); 85 } 86 free(hash); 87 } 88 89 static inline unsigned int hash_superfast(const char *key, unsigned int len) 90 { 91 /* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html) 92 * used by WebCore (http://webkit.org/blog/8/hashtables-part-2/) 93 * EFL's eina and possible others. 94 */ 95 unsigned int tmp, hash = len, rem = len & 3; 96 97 len /= 4; 98 99 /* Main loop */ 100 for (; len > 0; len--) { 101 hash += get_unaligned((uint16_t *) key); 102 tmp = (get_unaligned((uint16_t *)(key + 2)) << 11) ^ hash; 103 hash = (hash << 16) ^ tmp; 104 key += 4; 105 hash += hash >> 11; 106 } 107 108 /* Handle end cases */ 109 switch (rem) { 110 case 3: 111 hash += get_unaligned((uint16_t *) key); 112 hash ^= hash << 16; 113 hash ^= key[2] << 18; 114 hash += hash >> 11; 115 break; 116 117 case 2: 118 hash += get_unaligned((uint16_t *) key); 119 hash ^= hash << 11; 120 hash += hash >> 17; 121 break; 122 123 case 1: 124 hash += *key; 125 hash ^= hash << 10; 126 hash += hash >> 1; 127 } 128 129 /* Force "avalanching" of final 127 bits */ 130 hash ^= hash << 3; 131 hash += hash >> 5; 132 hash ^= hash << 4; 133 hash += hash >> 17; 134 hash ^= hash << 25; 135 hash += hash >> 6; 136 137 return hash; 138 } 139 140 /* 141 * add or replace key in hash map. 142 * 143 * none of key or value are copied, just references are remembered as is, 144 * make sure they are live while pair exists in hash! 145 */ 146 int hash_add(struct hash *hash, const char *key, const void *value) 147 { 148 unsigned int keylen = strlen(key); 149 unsigned int hashval = hash_superfast(key, keylen); 150 unsigned int pos = hashval & (hash->n_buckets - 1); 151 struct hash_bucket *bucket = hash->buckets + pos; 152 struct hash_entry *entry, *entry_end; 153 154 if (bucket->used + 1 >= bucket->total) { 155 unsigned new_total = bucket->total + hash->step; 156 size_t size = new_total * sizeof(struct hash_entry); 157 struct hash_entry *tmp = realloc(bucket->entries, size); 158 if (tmp == NULL) 159 return -errno; 160 bucket->entries = tmp; 161 bucket->total = new_total; 162 } 163 164 entry = bucket->entries; 165 entry_end = entry + bucket->used; 166 for (; entry < entry_end; entry++) { 167 int c = strcmp(key, entry->key); 168 if (c == 0) { 169 if (hash->free_value) 170 hash->free_value((void *)entry->value); 171 entry->key = key; 172 entry->value = value; 173 return 0; 174 } else if (c < 0) { 175 memmove(entry + 1, entry, 176 (entry_end - entry) * sizeof(struct hash_entry)); 177 break; 178 } 179 } 180 181 entry->key = key; 182 entry->value = value; 183 bucket->used++; 184 hash->count++; 185 return 0; 186 } 187 188 /* similar to hash_add(), but fails if key already exists */ 189 int hash_add_unique(struct hash *hash, const char *key, const void *value) 190 { 191 unsigned int keylen = strlen(key); 192 unsigned int hashval = hash_superfast(key, keylen); 193 unsigned int pos = hashval & (hash->n_buckets - 1); 194 struct hash_bucket *bucket = hash->buckets + pos; 195 struct hash_entry *entry, *entry_end; 196 197 if (bucket->used + 1 >= bucket->total) { 198 unsigned new_total = bucket->total + hash->step; 199 size_t size = new_total * sizeof(struct hash_entry); 200 struct hash_entry *tmp = realloc(bucket->entries, size); 201 if (tmp == NULL) 202 return -errno; 203 bucket->entries = tmp; 204 bucket->total = new_total; 205 } 206 207 entry = bucket->entries; 208 entry_end = entry + bucket->used; 209 for (; entry < entry_end; entry++) { 210 int c = strcmp(key, entry->key); 211 if (c == 0) 212 return -EEXIST; 213 else if (c < 0) { 214 memmove(entry + 1, entry, 215 (entry_end - entry) * sizeof(struct hash_entry)); 216 break; 217 } 218 } 219 220 entry->key = key; 221 entry->value = value; 222 bucket->used++; 223 hash->count++; 224 return 0; 225 } 226 227 static int hash_entry_cmp(const void *pa, const void *pb) 228 { 229 const struct hash_entry *a = pa; 230 const struct hash_entry *b = pb; 231 return strcmp(a->key, b->key); 232 } 233 234 void *hash_find(const struct hash *hash, const char *key) 235 { 236 unsigned int keylen = strlen(key); 237 unsigned int hashval = hash_superfast(key, keylen); 238 unsigned int pos = hashval & (hash->n_buckets - 1); 239 const struct hash_bucket *bucket = hash->buckets + pos; 240 const struct hash_entry se = { 241 .key = key, 242 .value = NULL 243 }; 244 const struct hash_entry *entry = bsearch( 245 &se, bucket->entries, bucket->used, 246 sizeof(struct hash_entry), hash_entry_cmp); 247 if (entry == NULL) 248 return NULL; 249 return (void *)entry->value; 250 } 251 252 int hash_del(struct hash *hash, const char *key) 253 { 254 unsigned int keylen = strlen(key); 255 unsigned int hashval = hash_superfast(key, keylen); 256 unsigned int pos = hashval & (hash->n_buckets - 1); 257 unsigned int steps_used, steps_total; 258 struct hash_bucket *bucket = hash->buckets + pos; 259 struct hash_entry *entry, *entry_end; 260 const struct hash_entry se = { 261 .key = key, 262 .value = NULL 263 }; 264 265 entry = bsearch(&se, bucket->entries, bucket->used, 266 sizeof(struct hash_entry), hash_entry_cmp); 267 if (entry == NULL) 268 return -ENOENT; 269 270 if (hash->free_value) 271 hash->free_value((void *)entry->value); 272 273 entry_end = bucket->entries + bucket->used; 274 memmove(entry, entry + 1, 275 (entry_end - entry) * sizeof(struct hash_entry)); 276 277 bucket->used--; 278 hash->count--; 279 280 steps_used = bucket->used / hash->step; 281 steps_total = bucket->total / hash->step; 282 if (steps_used + 1 < steps_total) { 283 size_t size = (steps_used + 1) * 284 hash->step * sizeof(struct hash_entry); 285 struct hash_entry *tmp = realloc(bucket->entries, size); 286 if (tmp) { 287 bucket->entries = tmp; 288 bucket->total = (steps_used + 1) * hash->step; 289 } 290 } 291 292 return 0; 293 } 294 295 unsigned int hash_get_count(const struct hash *hash) 296 { 297 return hash->count; 298 } 299 300 void hash_iter_init(const struct hash *hash, struct hash_iter *iter) 301 { 302 iter->hash = hash; 303 iter->bucket = 0; 304 iter->entry = -1; 305 } 306 307 bool hash_iter_next(struct hash_iter *iter, const char **key, 308 const void **value) 309 { 310 const struct hash_bucket *b = iter->hash->buckets + iter->bucket; 311 const struct hash_entry *e; 312 313 iter->entry++; 314 315 if (iter->entry >= b->used) { 316 iter->entry = 0; 317 318 for (iter->bucket++; iter->bucket < iter->hash->n_buckets; 319 iter->bucket++) { 320 b = iter->hash->buckets + iter->bucket; 321 322 if (b->used > 0) 323 break; 324 } 325 326 if (iter->bucket >= iter->hash->n_buckets) 327 return false; 328 } 329 330 e = b->entries + iter->entry; 331 332 if (value != NULL) 333 *value = e->value; 334 if (key != NULL) 335 *key = e->key; 336 337 return true; 338 } 339