ei_hash *ei_hash_newtab(int tabsize) { ei_hash *tab=NULL; int bucketpos=sizeof(*tab); /* make sure size is odd, then increase until prime */ tabsize |= 0x1; while (!ei_isprime(tabsize)) tabsize +=2; /* we will only do one malloc, so "sizeof(*tab)" * must be adjusted to align tab->tab properly */ ei_align(bucketpos); /* single malloc, then fill in all fields */ if ((tab = malloc(bucketpos + (tabsize * (sizeof(*(tab->tab))))))) { tab->tab = (ei_bucket **)((char *)tab + bucketpos); memset(tab->tab,0,tabsize*sizeof(*(tab->tab))); tab->hash = ei_dohash; tab->size = tabsize; tab->npos = 0; tab->nelem = 0; tab->freelist = NULL; } return tab; }
/* move the elements from oldtab to a new table newsize. The old table * is freed and the caller should discard the pointer. On failure * (i.e. if malloc fails) return the old table and do nothing. */ ei_hash *ei_hash_resize(ei_hash *oldtab, int newsize) { ei_hash *newtab=NULL; ei_bucket *b, *next; int i,h; /* make sure size is odd, then increase until prime */ newsize |= 0x1; while (!ei_isprime(newsize)) newsize +=2; if (newsize == oldtab->size) return oldtab; /* make a new table */ if (!(newtab = ei_hash_newtab(newsize))) return oldtab; newtab->hash = oldtab->hash; /* move the buckets, rehashing */ /* note that this will reverse the order of any chains */ for (i=0; i<oldtab->size; i++) { b=oldtab->tab[i]; while (b) { next = b->next; h = b->rawhash % newtab->size; b->next=newtab->tab[h]; if (!newtab->tab[h]) newtab->npos++; newtab->tab[h]=b; b = next; } } /* the new table has the same number of elements as the old one */ newtab->nelem = oldtab->nelem; /* the new table takes over the freelist from the old one */ newtab->freelist = oldtab->freelist; /* now it's safe to remove the old table */ free(oldtab); return newtab; }