00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <stddef.h>
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024
00025 #include <ccn/hashtb.h>
00026
00027 struct node;
00028 struct node {
00029 struct node* link;
00030 size_t hash;
00031 size_t keysize;
00032 size_t extsize;
00033
00034 };
00035 #define DATA(ht, p) ((void *)((p) + 1))
00036 #define KEY(ht, p) ((unsigned char *)((p) + 1) + ht->item_size)
00037
00038 #define CHECKHTE(ht, hte) ((uintptr_t)((hte)->priv[1]) == ~(uintptr_t)(ht))
00039 #define MARKHTE(ht, hte) ((hte)->priv[1] = (void*)~(uintptr_t)(ht))
00040
00041 struct hashtb {
00042 struct node **bucket;
00043 size_t item_size;
00044 unsigned n_buckets;
00045 int n;
00046 int refcount;
00047 struct node *deferred;
00048 struct hashtb_param param;
00049 };
00050
00051 size_t
00052 hashtb_hash(const unsigned char *key, size_t key_size)
00053 {
00054 size_t h;
00055 size_t i;
00056 for (h = key_size + 23, i = 0; i < key_size; i++)
00057 h = ((h << 6) ^ (h >> 27)) + key[i];
00058 return(h);
00059 }
00060
00061 struct hashtb *
00062 hashtb_create(size_t item_size, const struct hashtb_param *param)
00063 {
00064 struct hashtb *ht;
00065 ht = calloc(1, sizeof(*ht));
00066 if (ht != NULL) {
00067 ht->item_size = item_size;
00068 ht->n = 0;
00069 ht->n_buckets = 7;
00070 ht->bucket = calloc(ht->n_buckets, sizeof(ht->bucket[0]));
00071 if (ht->bucket == NULL) {
00072 free(ht);
00073 return (NULL);
00074 }
00075 if (param != NULL)
00076 ht->param = *param;
00077 }
00078 return(ht);
00079 }
00080
00081 void *
00082 hashtb_get_param(struct hashtb *ht, struct hashtb_param *param)
00083 {
00084 if (param != NULL)
00085 *param = ht->param;
00086 return(ht->param.finalize_data);
00087 }
00088
00089 void
00090 hashtb_destroy(struct hashtb **htp)
00091 {
00092 if (*htp != NULL) {
00093 struct hashtb_enumerator tmp;
00094 struct hashtb_enumerator *e = hashtb_start(*htp, &tmp);
00095 while (e->key != NULL)
00096 hashtb_delete(e);
00097 hashtb_end(&tmp);
00098 if ((*htp)->refcount == 0) {
00099 free((*htp)->bucket);
00100 free(*htp);
00101 *htp = NULL;
00102 }
00103 else
00104 abort();
00105 }
00106 }
00107
00108 int
00109 hashtb_n(struct hashtb *ht)
00110 {
00111 return(ht->n);
00112 }
00113
00114 void *
00115 hashtb_lookup(struct hashtb *ht, const void *key, size_t keysize)
00116 {
00117 struct node *p;
00118 size_t h;
00119 if (key == NULL)
00120 return(NULL);
00121 h = hashtb_hash(key, keysize);
00122 for (p = ht->bucket[h % ht->n_buckets]; p != NULL; p = p->link) {
00123 if (p->hash < h)
00124 continue;
00125 if (p->hash > h)
00126 break;
00127 if (keysize == p->keysize && 0 == memcmp(key, KEY(ht, p), keysize))
00128 return(DATA(ht, p));
00129 }
00130 return(NULL);
00131 }
00132
00133 static void
00134 setpos(struct hashtb_enumerator *hte, struct node **pp)
00135 {
00136 struct hashtb *ht = hte->ht;
00137 struct node *p = NULL;
00138 hte->priv[0] = pp;
00139 if (pp != NULL)
00140 p = *pp;
00141 if (p == NULL) {
00142 hte->key = NULL;
00143 hte->keysize = 0;
00144 hte->extsize = 0;
00145 hte->data = NULL;
00146 }
00147 else {
00148 hte->key = KEY(ht, p);
00149 hte->keysize = p->keysize;
00150 hte->extsize = p->extsize;
00151 hte->data = DATA(ht, p);
00152 }
00153 }
00154
00155 static struct node **
00156 scan_buckets(struct hashtb *ht, unsigned b)
00157 {
00158 for (; b < ht->n_buckets; b++)
00159 if (ht->bucket[b] != NULL)
00160 return &(ht->bucket[b]);
00161 return(NULL);
00162 }
00163
00164 #define MAX_ENUMERATORS 30
00165 struct hashtb_enumerator *
00166 hashtb_start(struct hashtb *ht, struct hashtb_enumerator *hte)
00167 {
00168 MARKHTE(ht, hte);
00169 hte->datasize = ht->item_size;
00170 hte->ht = ht;
00171 ht->refcount++;
00172 if (ht->refcount > MAX_ENUMERATORS)
00173 abort();
00174 setpos(hte, scan_buckets(ht, 0));
00175 return(hte);
00176 }
00177
00178 void
00179 hashtb_end(struct hashtb_enumerator *hte)
00180 {
00181 struct hashtb *ht = hte->ht;
00182 struct node *p;
00183 hashtb_finalize_proc f;
00184 if (!CHECKHTE(ht, hte) || ht->refcount <= 0) abort();
00185 if (ht->refcount == 1) {
00186
00187 f = ht->param.finalize;
00188 while (ht->deferred != NULL) {
00189 setpos(hte, &(ht->deferred));
00190 if (f != NULL)
00191 (*f)(hte);
00192 p = ht->deferred;
00193 ht->deferred = p->link;
00194 free(p);
00195 }
00196 }
00197 hte->priv[0] = 0;
00198 hte->priv[1] = 0;
00199 ht->refcount--;
00200 }
00201
00202 void
00203 hashtb_next(struct hashtb_enumerator *hte)
00204 {
00205 struct node **pp = hte->priv[0];
00206 struct node **ppp;
00207 if (pp != NULL) {
00208 ppp = pp;
00209 pp = &((*pp)->link);
00210 if (*pp == NULL)
00211 pp = scan_buckets(hte->ht, ((*ppp)->hash % hte->ht->n_buckets) + 1);
00212 }
00213 setpos(hte, pp);
00214 }
00215
00216 int
00217 hashtb_seek(struct hashtb_enumerator *hte, const void *key, size_t keysize, size_t extsize)
00218 {
00219 struct node *p = NULL;
00220 struct hashtb *ht = hte->ht;
00221 struct node **pp;
00222 size_t h;
00223 if (key == NULL) {
00224 setpos(hte, NULL);
00225 return(-1);
00226 }
00227 if (ht->refcount == 1 && ht->n > ht->n_buckets * 3) {
00228 ht->refcount--;
00229 hashtb_rehash(ht, 2 * ht->n + 1);
00230 ht->refcount++;
00231 }
00232 h = hashtb_hash(key, keysize);
00233 pp = &(ht->bucket[h % ht->n_buckets]);
00234 for (p = *pp; p != NULL; pp = &(p->link), p = p->link) {
00235 if (p->hash < h)
00236 continue;
00237 if (p->hash > h)
00238 break;
00239 if (keysize == p->keysize && 0 == memcmp(key, KEY(ht, p), keysize)) {
00240 setpos(hte, pp);
00241 return(HT_OLD_ENTRY);
00242 }
00243 }
00244 p = calloc(1, sizeof(*p) + ht->item_size + keysize + extsize);
00245 if (p == NULL) {
00246 setpos(hte, NULL);
00247 return(-1);
00248 }
00249 memcpy(KEY(ht, p), key, keysize + extsize);
00250 p->hash = h;
00251 p->keysize = keysize;
00252 p->extsize = extsize;
00253 p->link = *pp;
00254 *pp = p;
00255 hte->ht->n += 1;
00256 setpos(hte, pp);
00257 return(HT_NEW_ENTRY);
00258 }
00259
00260 void
00261 hashtb_delete(struct hashtb_enumerator *hte)
00262 {
00263 struct hashtb *ht = hte->ht;
00264 struct node **pp = hte->priv[0];
00265 struct node *p = *pp;
00266 if ((p != NULL) && CHECKHTE(ht, hte) && KEY(ht, p) == hte->key) {
00267 *pp = p->link;
00268 if (*pp == NULL)
00269 pp = scan_buckets(hte->ht, (p->hash % hte->ht->n_buckets) + 1);
00270 hte->ht->n -= 1;
00271 if (ht->refcount == 1) {
00272 hashtb_finalize_proc f = ht->param.finalize;
00273 if (f != NULL)
00274 (*f)(hte);
00275 free(p);
00276 }
00277 else {
00278 p->link = ht->deferred;
00279 ht->deferred = p;
00280 }
00281 setpos(hte, pp);
00282 }
00283 }
00284
00285 void
00286 hashtb_rehash(struct hashtb *ht, unsigned n_buckets)
00287 {
00288 struct node **bucket = NULL;
00289 struct node **pp;
00290 struct node *p;
00291 struct node *q;
00292 size_t h;
00293 unsigned i;
00294 unsigned b;
00295 if (ht->refcount != 0 || n_buckets < 1 || n_buckets == ht->n_buckets)
00296 return;
00297 bucket = calloc(n_buckets, sizeof(bucket[0]));
00298 if (bucket == NULL) return;
00299 for (i = 0; i < ht->n_buckets; i++) {
00300 for (p = ht->bucket[i]; p != NULL; p = q) {
00301 q = p->link;
00302 h = p->hash;
00303 b = h % n_buckets;
00304 for (pp = &bucket[b]; *pp != NULL && ((*pp)->hash < h); pp = &((*pp)->link))
00305 continue;
00306 p->link = *pp;
00307 *pp = p;
00308 }
00309 }
00310 free(ht->bucket);
00311 ht->bucket = bucket;
00312 ht->n_buckets = n_buckets;
00313 }
00314