server-1.12/plugins/common/hashtable.c

249 lines
7.7 KiB
C

/*****************************************************************************/
/* hashtable.c */
/* Author: Alex Schultz, 2006 */
/* Based upon shstr.c, origionally written by Kjetil T. Homme, Oslo 1992. */
/*****************************************************************************/
/* This is a pointer association hash table library for plugins to use with */
/* a simple interface. This file is named as it is for other hash table */
/* types to be added if people wish to. */
/*****************************************************************************/
/* That code is placed under the GNU General Public Licence (GPL) */
/* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints) */
/*****************************************************************************/
/* CrossFire, A Multiplayer game for X-windows */
/* */
/* Copyright (C) 2000 Mark Wedel */
/* Copyright (C) 1992 Frank Tore Johansen */
/* */
/* This program 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 of the License, or */
/* (at your option) any later version. */
/* */
/* This program 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 this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/*****************************************************************************/
#include <string.h>
#include <stdlib.h>
#ifdef WIN32
#include <global.h>
typedef UINT_PTR uintptr_t;
#include <malloc.h>
#else
#include <stdint.h>
#include <autoconf.h>
#endif
#ifdef HAVE_LIBDMALLOC
#include <dmalloc.h>
#endif
#include <hashtable.h>
/**
* Initialises the hash table for a pointer association table.
*
* @param hash_table
* Pointer to the hash table to initialise.
*/
void init_ptr_assoc_table(ptr_assoc **hash_table) {
(void)memset((void *)hash_table, 0, PTR_ASSOC_TABLESIZE*sizeof(ptr_assoc *));
}
/**
* Hashing-function used by the pointer association library. Currently
* just takes the pointer modulus the table size (which should be a prime
* number).
*
* @param ptr
* The pointer to hash.
*
* @return
* The returned hash value.
*/
static int hashptr(void *ptr) {
return (int)((uintptr_t)ptr%PTR_ASSOC_TABLESIZE);
}
/**
* Allocates and initialises a new ptr_assoc structure.
*
* @param key
* The key to lookup by in the association.
* @param value
* The value to store with the key.
*
* @return
* The new ptr_assoc structure.
*/
static ptr_assoc *new_ptr_assoc(void *key, void *value) {
ptr_assoc *assoc;
assoc = (ptr_assoc *)malloc(sizeof(ptr_assoc));
assoc->previous = NULL;
assoc->array = NULL;
assoc->next = NULL;
assoc->key = key;
assoc->value = value;
return assoc;
}
/**
* Adds a value to a hash table which one can lookup with key.
*
* @param hash_table
* Pointer to the hash table to add to.
* @param key
* The key to lookup by in the association.
* @param value
* The value to store with the key.
*/
void add_ptr_assoc(ptr_assoc **hash_table, void *key, void *value) {
ptr_assoc *assoc;
int ind;
ind = hashptr(key);
assoc = hash_table[ind];
/* Is there an entry for that hash? */
if (assoc) {
/* Simple case first: See if the first pointer matches. */
if (key != assoc->key) {
/* Apparantly, a association with the same hash value has this
* slot. We must see in the list if this perticular key has
* been registered before.
*/
while (assoc->next) {
assoc = assoc->next;
if (key != assoc->key) {
/* This wasn't the right key... */
continue;
}
/* We found an entry for this key. Make sure the value
* is set as we want it.
*/
assoc->value = value;
return;
}
/* There are no occurences of this key in the hash table. */
{
ptr_assoc *new_assoc;
new_assoc = new_ptr_assoc(key, value);
assoc->next = new_assoc;
new_assoc->previous = assoc;
return;
}
}
return;
} else {
/* The string isn't registered, and the slot is empty. */
hash_table[ind] = new_ptr_assoc(key, value);
hash_table[ind]->array = &(hash_table[ind]);
return;
}
}
/**
* Find the ptr_assoc with a given key.
*
* @param hash_table
* Pointer to the hash table to search.
* @param key
* The key to lookup by in the association.
*
* @return
* The ptr_assoc that is found, or null if none is found.
*/
static ptr_assoc *find_ptr_assoc(ptr_assoc **hash_table, void *key) {
ptr_assoc *assoc;
int ind;
ind = hashptr(key);
assoc = hash_table[ind];
/* Is there an entry for that hash? */
if (assoc) {
/* Simple case first: Is the first key the right one? */
if (assoc->key == key) {
return assoc;
} else {
/* Recurse through the linked list, if there's one. */
while (assoc->next) {
assoc = assoc->next;
if (assoc->key == key) {
return assoc;
}
}
/* No match. Fall through. */
}
}
return NULL;
}
/**
* Find the value associated with a given key.
*
* @param hash_table
* Pointer to the hash table to search.
* @param key
* The key to lookup by in the association.
*
* @return
* The value associated with the key.
*/
void *find_assoc_value(ptr_assoc **hash_table, void *key) {
ptr_assoc *assoc;
assoc = find_ptr_assoc(hash_table, key);
if (!assoc)
return NULL;
return assoc->value;
}
/**
* Remove the association with a given key.
*
* @param hash_table
* Pointer to the hash table to search.
* @param key
* The key to lookup by in the association.
*/
void free_ptr_assoc(ptr_assoc **hash_table, void *key) {
ptr_assoc *assoc;
assoc = find_ptr_assoc(hash_table, key);
if (!assoc)
return;
if (assoc->array) {
/* We must put a new value into the hash_table[].
*/
if (assoc->next) {
*(assoc->array) = assoc->next;
assoc->next->previous = NULL;
assoc->next->array = assoc->array;
} else {
*(assoc->array) = NULL;
}
free(assoc);
} else {
/* Relink and free this struct.
*/
if (assoc->next)
assoc->next->previous = assoc->previous;
assoc->previous->next = assoc->next;
free(assoc);
}
}