hashtab.c

来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 268 行

C
268
字号
/* * 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"/* 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 {	const 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 const void	*const DELETED = (const 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 (0);	}	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, const void *ptr){	int	index;	void	*rtn;	if (NEED_RESIZE(tab)) {		if (hashResize(tab) == 0) {			/* XXX OutOfMemoryError? */			return (0);		}	}	index = hashFindSlot(tab, ptr);	assert(index != -1);	if (tab->list[index] == NULL || tab->list[index] == DELETED) {		tab->list[index] = ptr;		tab->count++;	}	rtn = (void *) tab->list[index];	return(rtn);}/* * Remove a pointer. If the pointer is not itself in the table, * we don't remove it. */voidhashRemove(hashtab_t tab, const void *ptr){	int index;	index = hashFindSlot(tab, ptr);	assert(index != -1);	if (tab->list[index] != NULL	    && tab->list[index] != DELETED	    && tab->list[index] == ptr) {		tab->count--;		tab->list[index] = DELETED;	}}/* * Find a matching pointer in the table. */void *hashFind(hashtab_t tab, const void *ptr){	int index;	void *rtn;	index = hashFindSlot(tab, ptr);	assert(index != -1);	rtn = (tab->list[index] == DELETED) ?		NULL : (void *) tab->list[index];	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 index, deletedIndex = -1;	/* Sanity check */	if (ptr == NULL || ptr == DELETED) {		return(-1);	}	/* Find slot */	index = startIndex;	for (;;) {		const void **const ptr2 = &tab->list[index];		if (*ptr2 == NULL) {			return (deletedIndex >= 0) ? deletedIndex : index;		}		if (*ptr2 == DELETED) {			if (deletedIndex == -1) {				deletedIndex = index;			}		} else if (*ptr2 == ptr || (*tab->comp)(ptr, *ptr2) == 0) {			return(index);		}		index = (index + step) & (tab->size - 1);		/* Check for looping all the way through the table */		if (index == 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;	const void **newList;	int index;	/* 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 (0);	}	/* Rehash old list contents into new list */	for (index = tab->size - 1; index >= 0; index--) {		const void *ptr = tab->list[index];		if (ptr != NULL && ptr != DELETED) {			const int hash = (*tab->hash)(ptr);			const int step = LIST_STEP(hash);			int index;			for (index = hash & (newSize - 1);			    newList[index] != NULL;			    index = (index + step) & (newSize - 1));			newList[index] = ptr;		}	}	/* Update table */	if (tab->dealloc) {		tab->dealloc(tab->list);	} else {		KFREE(tab->list);	}	tab->list = newList;	tab->size = newSize;	return (tab);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?