map.c (2153B)
1 /* Written by Kris Maglione */ 2 /* Public domain */ 3 #include <assert.h> 4 #include <string.h> 5 #include <stuff/util.h> 6 7 /* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */ 8 9 struct MapEnt { 10 ulong hash; 11 const char* key; 12 void* val; 13 MapEnt* next; 14 }; 15 16 MapEnt *NM; 17 18 /* By Dan Bernstein. Public domain. */ 19 static ulong 20 hash(const char *str) { 21 ulong h; 22 23 h = 5381; 24 while (*str != '\0') { 25 h += h << 5; /* h *= 33 */ 26 h ^= *str++; 27 } 28 return h; 29 } 30 31 static void 32 insert(Map *m, MapEnt **e, ulong val, const char *key) { 33 MapEnt *te; 34 35 m->nmemb++; 36 te = emallocz(sizeof *te); 37 te->hash = val; 38 te->key = key; 39 te->next = *e; 40 *e = te; 41 } 42 43 static MapEnt** 44 map_getp(Map *map, ulong val, int create) { 45 MapEnt **e; 46 47 e = &map->bucket[val%map->nhash]; 48 for(; *e; e = &(*e)->next) 49 if((*e)->hash >= val) break; 50 if(*e == nil || (*e)->hash != val) { 51 if(create) 52 insert(map, e, val, nil); 53 else 54 e = &NM; 55 } 56 return e; 57 } 58 59 static MapEnt** 60 hash_getp(Map *map, const char *str, int create) { 61 MapEnt **e; 62 ulong h; 63 int cmp; 64 65 h = hash(str); 66 e = map_getp(map, h, create); 67 if(*e && (*e)->key == nil) 68 (*e)->key = estrdup(str); 69 else { 70 SET(cmp); 71 for(; *e; e = &(*e)->next) 72 if((*e)->hash > h || (cmp = strcmp((*e)->key, str)) >= 0) 73 break; 74 if(*e == nil || (*e)->hash > h || cmp > 0) 75 if(create) 76 insert(map, e, h, estrdup(str)); 77 } 78 return e; 79 } 80 81 void** 82 map_get(Map *map, ulong val, bool create) { 83 MapEnt *e; 84 85 e = *map_getp(map, val, create); 86 return e ? &e->val : nil; 87 } 88 89 void** 90 hash_get(Map *map, const char *str, bool create) { 91 MapEnt *e; 92 93 e = *hash_getp(map, str, create); 94 return e ? &e->val : nil; 95 } 96 97 void* 98 map_rm(Map *map, ulong val) { 99 MapEnt **e, *te; 100 void *ret; 101 102 ret = nil; 103 e = map_getp(map, val, 0); 104 if(*e) { 105 te = *e; 106 ret = te->val; 107 *e = te->next; 108 assert(map->nmemb-- > 0); 109 free(te); 110 } 111 return ret; 112 } 113 114 void* 115 hash_rm(Map *map, const char *str) { 116 MapEnt **e, *te; 117 void *ret; 118 119 ret = nil; 120 e = hash_getp(map, str, 0); 121 if(*e) { 122 te = *e; 123 ret = te->val; 124 *e = te->next; 125 assert(map->nmemb-- > 0); 126 free((void*)(uintptr_t)te->key); 127 free(te); 128 } 129 return ret; 130 } 131