xl_hash.c

#include "xl_hash.h"

xl_hash *xl_hash_init(xl_hash_type *type){
	return xl_hash_init_with_size(type, 0);
}

xl_hash *xl_hash_init_with_size(xl_hash_type *type, XL_HASH_KEY_TYPE size){
	xl_hash *hash = (xl_hash *)calloc(1, sizeof(xl_hash));

	hash->type = type;
	hash->size = size;
	hash->entry = (xl_hash_entry **)calloc(size, sizeof(xl_hash_entry *));

	return hash;
}

xl_hash_entry *xl_hash_find(xl_hash *hash, XL_KEY_TYPE key){
	xl_hash_entry *entry = hash->entry[XL_HASH_CALC(hash, key)];

	for(; entry != NULL; entry = entry->next){
		if(XL_HASH_KEY_COMP(hash, key, entry->key))return entry;
	}

	return NULL;
}

int xl_hash_delete(xl_hash *hash, XL_KEY_TYPE key){
	xl_hash_entry *entry = xl_hash_find(hash, key);

	if(entry != NULL){
		if(entry->pre) entry->pre->next = entry->next;
		else hash->entry[XL_HASH_CALC(hash, key)] = entry->next;
		if(entry->next)entry->next->pre =entry->pre;
		free(entry->value);
		free(entry->key);
		free(entry);
		return 1;
	}

	return 0;
}

xl_hash_entry *xl_hash_new_entry(xl_hash *hash, XL_VALUE_TYPE val, XL_KEY_TYPE key){
	xl_hash_entry *entry = calloc(1, sizeof(xl_hash_entry));

	entry->value = (XL_VALUE_TYPE)calloc(1, hash->type->value_size);
	entry->key   = (XL_KEY_TYPE)  calloc(1, hash->type->key_size);
	memcpy(entry->value, val, hash->type->value_size);
	memcpy(entry->key  , key, hash->type->key_size);
	entry->pre   = NULL;
	entry->next  = NULL;

	return entry;
}

int xl_hash_add_first(xl_hash *hash, XL_VALUE_TYPE val, XL_KEY_TYPE key){
	XL_HASH_KEY_TYPE hash_key = XL_HASH_CALC(hash, key);
	xl_hash_entry **p_entry = hash->entry + hash_key;
	xl_hash_entry *new_entry = xl_hash_new_entry(hash, val, key);

	new_entry->next = *p_entry;
	*p_entry = new_entry;

	return 1;
}

int xl_hash_add_last(xl_hash *hash, XL_VALUE_TYPE val, XL_KEY_TYPE key){
	XL_HASH_KEY_TYPE hash_key = XL_HASH_CALC(hash, key);
	xl_hash_entry *entry = hash->entry[hash_key];
	xl_hash_entry *new_entry = xl_hash_new_entry(hash, val, key);

	if(entry == NULL){
		hash->entry[hash_key] = new_entry;
	}
	else{
		for(; entry->next != NULL; entry = entry->next);
		new_entry->pre = entry;
		entry->next = new_entry;
	}

	return 1;
}

void xl_hash_foreach(xl_hash *hash, void (*func)(XL_VALUE_TYPE)){
	int i;
	xl_hash_entry *entry = NULL, *next = NULL;

	for(i = 0; i < hash->size; i++){
		for(entry = hash->entry[i]; entry != NULL; entry = next){
			next = entry->next;
			(*func)(entry->value);
		}
	}
}

xl_hash *xl_hash_lookup(xl_hash *hash, int (*func)(XL_VALUE_TYPE)){
	int i;
	xl_hash_entry *entry = NULL, *next = NULL;
	xl_hash *new_hash = xl_hash_init_with_size(hash->type, hash->size);

	for(i = 0; i < hash->size; i++){
		for(entry = hash->entry[i]; entry != NULL; entry = next){
			next = entry->next;
			if((*func)(entry->value))xl_hash_add_first(new_hash, entry->value, entry->key);
		}
	}
	return new_hash;
}

void xl_hash_free(xl_hash *hash){
	xl_hash_clear(hash);
	free(hash->entry);
	free(hash);
}

void xl_hash_clear(xl_hash *hash){
	int i;
	xl_hash_entry *entry = NULL, *next = NULL;

	for(i = 0; i < hash->size; i++){
		for(entry = hash->entry[i]; entry != NULL; entry = next){
			next = entry->next;
			free(entry->value);
			free(entry->key);
			free(entry);
		}
		hash->entry[i] = NULL;
	}
}