/* * hashtable.c * * Hash table handling for strings * * © 1994-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Dynamic Linking System (SDLS) * * SDLS is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * SDLS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with SDLS. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "hashtable.h" #include "crc32.h" /*----- Constants ---------------------------------------------------------*/ #define hash__SIZE 512 /* A respectable size table */ /* Note: must be power of 2 */ /*----- Some good ol' data structures -------------------------------------*/ typedef struct hash__link { struct hash__link *next; /* Link in hash table bucket */ struct hash__link *left; /* Link in ordinal tree */ struct hash__link *right; /* Link in ordinal tree */ unsigned int ord; /* Ordinal value */ char string[1]; /* String (unsized array) */ } hash__link; typedef struct hash__table { hash__link *tbl[hash__SIZE]; /* The actual hash table */ hash__link *root; /* The ordinal tree root */ } hash__table; /*----- Private code ------------------------------------------------------*/ #define hash__hash(s) (crc32(0,s,strlen(s),1) & (hash__SIZE - 1)) static int hash__addToTree(hash__link **root,hash__link *l) { if (*root) { if ((*root)->ord > l->ord) return (hash__addToTree(&(*root)->left,l)); else if ((*root)->ord < l->ord || l->ord == 0xFFFFFFFF) return (hash__addToTree(&(*root)->right,l)); else return (1); } else { *root=l; return (0); } } static void hash__traverse(hash__link *l, void (*func)(char *string, unsigned int ord, void *handle), void *handle) { if (l) { hash__traverse(l->left,func,handle); func(l->string,l->ord,handle); hash__traverse(l->right,func,handle); } } static void hash__dump(char *string,unsigned int ord,void *handle) { handle=handle; printf(" ** %s (%08x)\n",string,ord); } /*----- Public code -------------------------------------------------------*/ hashtable hash_create(void) { return (calloc(1,sizeof(hash__table))); } int hash_find(hashtable h,char *string) { int sh=hash__hash(string); hash__link *l; for (l=h->tbl[sh];l;l=l->next) { if (!strcmp(l->string,string)) return (1); } return (0); } int hash_add(hashtable h,char *string) { return (hash_addWithOrd(h,string,0xFFFFFFFF)); } int hash_addWithOrd(hashtable h,char *string,unsigned int ord) { int sh=hash__hash(string); hash__link *l; if (hash_find(h,string)) return (1); if (l=malloc(sizeof(hash__link)+strlen(string)),!l) return (0); strcpy(l->string,string); l->ord=ord; l->next=h->tbl[sh]; h->tbl[sh]=l; l->left=l->right=0; if (hash__addToTree(&h->root,l)) { l->ord=0xFFFFFFFF; hash__addToTree(&h->root,l); } return (1); } void hash_delete(hashtable h) { hash__link *l; hash__link *n; int i; for (i=0;itbl[i];l;l=n) { n=l->next; free(l); } } free(h); } int hash_subset(hashtable super, hashtable sub, void (*proc)(char *p)) { hash__link *l; int i; int s=1; for (i=0;itbl[i];l;l=l->next) { if (!hash_find(super,l->string)) { s=0; proc(l->string); } } } return (s); } void hash_dump(hashtable h) { hash_enumOrdered(h,hash__dump,0); } void hash_enumerate(hashtable h, void (*func)(char *string,void *handle), void *handle) { hash__link *l; int i; for (i=0;itbl[i];l;l=l->next) func(l->string,handle); } } void hash_enumOrdered(hashtable h, void (*func)(char *string, unsigned int ord, void *handle), void *handle) { hash__traverse(h->root,func,handle); } int hash_count(hashtable h) { int count=0; hash__link *l; int i; for (i=0;itbl[i];l;l=l->next) count++; } return (count); }