249 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			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);
 | 
						|
    }
 | 
						|
}
 |