| /* |
| * include/linux/ghash.h -- generic hashing with fuzzy retrieval |
| * |
| * (C) 1997 Thomas Schoebel-Theuer |
| * |
| * The algorithms implemented here seem to be a completely new invention, |
| * and I'll publish the fundamentals in a paper. |
| */ |
| |
| #ifndef _GHASH_H |
| #define _GHASH_H |
| /* HASHSIZE _must_ be a power of two!!! */ |
| |
| |
| #define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \ |
| \ |
| struct NAME##_table {\ |
| TYPE * hashtable[HASHSIZE];\ |
| TYPE * sorted_list;\ |
| int nr_entries;\ |
| };\ |
| \ |
| struct NAME##_ptrs {\ |
| TYPE * next_hash;\ |
| TYPE * prev_hash;\ |
| TYPE * next_sorted;\ |
| TYPE * prev_sorted;\ |
| }; |
| |
| #define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\ |
| \ |
| LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ |
| {\ |
| int ix = HASHFN(elem->KEY);\ |
| TYPE ** base = &tbl->hashtable[ix];\ |
| TYPE * ptr = *base;\ |
| TYPE * prev = NULL;\ |
| \ |
| tbl->nr_entries++;\ |
| while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ |
| base = &ptr->PTRS.next_hash;\ |
| prev = ptr;\ |
| ptr = *base;\ |
| }\ |
| elem->PTRS.next_hash = ptr;\ |
| elem->PTRS.prev_hash = prev;\ |
| if(ptr) {\ |
| ptr->PTRS.prev_hash = elem;\ |
| }\ |
| *base = elem;\ |
| \ |
| ptr = prev;\ |
| if(!ptr) {\ |
| ptr = tbl->sorted_list;\ |
| prev = NULL;\ |
| } else {\ |
| prev = ptr->PTRS.prev_sorted;\ |
| }\ |
| while(ptr) {\ |
| TYPE * next = ptr->PTRS.next_hash;\ |
| if(next && KEYCMP(next->KEY, elem->KEY)) {\ |
| prev = ptr;\ |
| ptr = next;\ |
| } else if(KEYCMP(ptr->KEY, elem->KEY)) {\ |
| prev = ptr;\ |
| ptr = ptr->PTRS.next_sorted;\ |
| } else\ |
| break;\ |
| }\ |
| elem->PTRS.next_sorted = ptr;\ |
| elem->PTRS.prev_sorted = prev;\ |
| if(ptr) {\ |
| ptr->PTRS.prev_sorted = elem;\ |
| }\ |
| if(prev) {\ |
| prev->PTRS.next_sorted = elem;\ |
| } else {\ |
| tbl->sorted_list = elem;\ |
| }\ |
| }\ |
| \ |
| LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ |
| {\ |
| TYPE * next = elem->PTRS.next_hash;\ |
| TYPE * prev = elem->PTRS.prev_hash;\ |
| \ |
| tbl->nr_entries--;\ |
| if(next)\ |
| next->PTRS.prev_hash = prev;\ |
| if(prev)\ |
| prev->PTRS.next_hash = next;\ |
| else {\ |
| int ix = HASHFN(elem->KEY);\ |
| tbl->hashtable[ix] = next;\ |
| }\ |
| \ |
| next = elem->PTRS.next_sorted;\ |
| prev = elem->PTRS.prev_sorted;\ |
| if(next)\ |
| next->PTRS.prev_sorted = prev;\ |
| if(prev)\ |
| prev->PTRS.next_sorted = next;\ |
| else\ |
| tbl->sorted_list = next;\ |
| }\ |
| \ |
| LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ |
| {\ |
| int ix = hashfn(pos);\ |
| TYPE * ptr = tbl->hashtable[ix];\ |
| while(ptr && KEYCMP(ptr->KEY, pos))\ |
| ptr = ptr->PTRS.next_hash;\ |
| if(ptr && !KEYEQ(ptr->KEY, pos))\ |
| ptr = NULL;\ |
| return ptr;\ |
| }\ |
| \ |
| LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\ |
| {\ |
| int ix;\ |
| int offset;\ |
| TYPE * ptr;\ |
| TYPE * next;\ |
| \ |
| ptr = tbl->sorted_list;\ |
| if(!ptr || KEYCMP(pos, ptr->KEY))\ |
| return NULL;\ |
| ix = HASHFN(pos);\ |
| offset = HASHSIZE;\ |
| do {\ |
| offset >>= 1;\ |
| next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\ |
| if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\ |
| && KEYCMP(ptr->KEY, next->KEY))\ |
| ptr = next;\ |
| } while(offset);\ |
| \ |
| for(;;) {\ |
| next = ptr->PTRS.next_hash;\ |
| if(next) {\ |
| if(KEYCMP(next->KEY, pos)) {\ |
| ptr = next;\ |
| continue;\ |
| }\ |
| }\ |
| next = ptr->PTRS.next_sorted;\ |
| if(next && KEYCMP(next->KEY, pos)) {\ |
| ptr = next;\ |
| continue;\ |
| }\ |
| return ptr;\ |
| }\ |
| return NULL;\ |
| } |
| |
| #define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \ |
| \ |
| struct NAME##_table {\ |
| TYPE * hashtable[HASHSIZE];\ |
| int nr_entries;\ |
| };\ |
| \ |
| struct NAME##_ptrs {\ |
| TYPE * next_hash;\ |
| TYPE * prev_hash;\ |
| }; |
| |
| #define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\ |
| \ |
| LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ |
| {\ |
| int ix = HASHFN(elem->KEY);\ |
| TYPE ** base = &tbl->hashtable[ix];\ |
| TYPE * ptr = *base;\ |
| TYPE * prev = NULL;\ |
| \ |
| tbl->nr_entries++;\ |
| while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ |
| base = &ptr->PTRS.next_hash;\ |
| prev = ptr;\ |
| ptr = *base;\ |
| }\ |
| elem->PTRS.next_hash = ptr;\ |
| elem->PTRS.prev_hash = prev;\ |
| if(ptr) {\ |
| ptr->PTRS.prev_hash = elem;\ |
| }\ |
| *base = elem;\ |
| }\ |
| \ |
| LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ |
| {\ |
| TYPE * next = elem->PTRS.next_hash;\ |
| TYPE * prev = elem->PTRS.prev_hash;\ |
| \ |
| tbl->nr_entries--;\ |
| if(next)\ |
| next->PTRS.prev_hash = prev;\ |
| if(prev)\ |
| prev->PTRS.next_hash = next;\ |
| else {\ |
| int ix = HASHFN(elem->KEY);\ |
| tbl->hashtable[ix] = next;\ |
| }\ |
| }\ |
| \ |
| LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ |
| {\ |
| int ix = hashfn(pos);\ |
| TYPE * ptr = tbl->hashtable[ix];\ |
| while(ptr && KEYCMP(ptr->KEY, pos))\ |
| ptr = ptr->PTRS.next_hash;\ |
| if(ptr && !KEYEQ(ptr->KEY, pos))\ |
| ptr = NULL;\ |
| return ptr;\ |
| } |
| |
| #endif |