hashtab.c
来自「基于LWVCL开发的库」· C语言 代码 · 共 275 行
C
275 行
/* * hashtab.c * * "Intern" hash table library * * Copyright (c) 1998 * Transvirtual Technologies, Inc. All rights reserved. */#include "config.h"#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "gtypes.h"#include "gc.h"#include "hashtab.h"#include "kaffe/jmalloc.h"/* Initial size */#define INITIAL_SIZE 1024/* When to increase size of hash table */#define NEED_RESIZE(tab) (4 * (tab)->count >= 3 * (tab)->size)/* Generate step from hash. Note that "step" must always be relatively prime to tab->size. */#define LIST_STEP(hash) (8 * (hash) + 7)/* Hashtable structure */struct _hashtab { void **list; /* List of pointers to whatever */ int count; /* Number of slots used in the list */ int size; /* Total size list; always a power of 2 */ compfunc_t comp; /* Comparison function */ hashfunc_t hash; /* Hash function */ allocfunc_t alloc; /* Allocation function */ freefunc_t dealloc; /* Free function */};/* Internal functions */static int hashFindSlot(hashtab_t, const void *ptr);static hashtab_t hashResize(hashtab_t tab);/* Indicates a deleted pointer */static void *const DELETED = (void *)&DELETED;/* * Create a new hashtable */hashtab_thashInit(hashfunc_t hash, compfunc_t comp, allocfunc_t alloc, freefunc_t dealloc){ hashtab_t tab; /* Use specified alloc function if one is given, fall back to KFREE */ if (alloc == 0) { tab = KCALLOC(1, sizeof(*tab)); } else { tab = alloc(sizeof(*tab)); } if (tab == 0) { return (NULL); } tab->hash = hash; tab->comp = comp; tab->alloc = alloc; tab->dealloc = dealloc; /* start out with initial size */ return (hashResize(tab));}/* * Destroy a hash table. */voidhashDestroy(hashtab_t tab){ int k; /* Remove all entries in the table */ for (k = 0; k < tab->size; k++) { if (tab->list[k] != NULL && tab->list[k] != DELETED) { hashRemove(tab, tab->list[k]); } } /* Nuke the table */ if (tab->dealloc) { tab->dealloc(tab->list); tab->dealloc(tab); } else { KFREE(tab->list); KFREE(tab); }}/* * Add an entry to the hash table. It's OK if the entry is already there, * or is equal to something that is already there. This returns the * matching pointer that is actually in the table. */void *hashAdd(hashtab_t tab, void *ptr){ int i; void *rtn; if (NEED_RESIZE(tab)) { if (hashResize(tab) == 0) { /* XXX OutOfMemoryError? */ return (NULL); } } i = hashFindSlot(tab, ptr); assert(i != -1); if (tab->list[i] == NULL || tab->list[i] == DELETED) { tab->list[i] = ptr; tab->count++; } rtn = tab->list[i]; return(rtn);}/* * Remove a pointer. If the pointer is not itself in the table, * we don't remove it. */voidhashRemove(hashtab_t tab, void *ptr){ int i; i = hashFindSlot(tab, ptr); assert(i != -1); if (tab->list[i] != NULL && tab->list[i] != DELETED && tab->list[i] == ptr) { tab->count--; tab->list[i] = DELETED; }}/* * Find a matching pointer in the table. */void *hashFind(hashtab_t tab, const void *ptr){ int i; void *rtn; i = hashFindSlot(tab, ptr); assert(i != -1); rtn = (tab->list[i] == DELETED) ? NULL : tab->list[i]; return(rtn);}/* * Find if an equal pointer is already in the table. If found, * return it; otherwise return a free slot for it. */static inthashFindSlot(hashtab_t tab, const void *ptr){ const int hash = (*tab->hash)(ptr); const int startIndex = hash & (tab->size - 1); const int step = LIST_STEP(hash); int i, deletedIndex = -1; /* Sanity check */ if (ptr == NULL || ptr == DELETED) { return(-1); } /* Find slot */ i = startIndex; for (;;) { void **const ptr2 = &tab->list[i]; if (*ptr2 == NULL) { return (deletedIndex >= 0) ? deletedIndex : i; } if (*ptr2 == DELETED) { if (deletedIndex == -1) { deletedIndex = i; } } else if (*ptr2 == ptr || (*tab->comp)(ptr, *ptr2) == 0) { return(i); } i = (i + step) & (tab->size - 1); /* Check for looping all the way through the table */ if (i == startIndex) { if (deletedIndex >= 0) { return(deletedIndex); } assert(!"hashFindSlot: no slot!"); } }}/* * Make the table bigger. * Return the new table or null if the allocation failed. * * It is okay to remove entries from the table while the allocation * function is invoked. */static hashtab_thashResize(hashtab_t tab){ const int newSize = (tab->size > 0) ? (tab->size * 2) : INITIAL_SIZE; void **newList; void **oldList; int i; /* Get a bigger list */ if (tab->alloc) { newList = tab->alloc(newSize * sizeof(*newList)); } else { newList = KCALLOC(newSize, sizeof(*newList)); } /* It is possible that the table no longer needs resizing, for * instance because a garbage collection happened and removed * entries, for instance when uninterning strings. */ if (!NEED_RESIZE(tab)) { if (tab->dealloc) { tab->dealloc(newList); } else { KFREE(newList); } return (tab); } if (newList == NULL) { return (NULL); } /* Rehash old list contents into new list */ for (i = tab->size - 1; i >= 0; i--) { void *ptr = tab->list[i]; if (ptr != NULL && ptr != DELETED) { const int hash = (*tab->hash)(ptr); const int step = LIST_STEP(hash); int j; for (j = hash & (newSize - 1); newList[j] != NULL; j = (j + step) & (newSize - 1)); newList[j] = ptr; } } /* Update table. The operation is atomic as the lock * is held by the owner of the hashtable. */ oldList = tab->list; tab->list = newList; tab->size = newSize; /* Free the old table */ if (tab->dealloc) { tab->dealloc(oldList); } else { KFREE(oldList); } return (tab);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?