Blame lib/Xm/Xpmhashtab.c

Packit b099d7
/* $XConsortium: Xpmhashtab.c /main/2 1996/09/20 08:15:27 pascale $ */
Packit b099d7
/*
Packit b099d7
 * Copyright (C) 1989-95 GROUPE BULL
Packit b099d7
 *
Packit b099d7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b099d7
 * of this software and associated documentation files (the "Software"), to
Packit b099d7
 * deal in the Software without restriction, including without limitation the
Packit b099d7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b099d7
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b099d7
 * furnished to do so, subject to the following conditions:
Packit b099d7
 *
Packit b099d7
 * The above copyright notice and this permission notice shall be included in
Packit b099d7
 * all copies or substantial portions of the Software.
Packit b099d7
 *
Packit b099d7
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b099d7
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b099d7
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Packit b099d7
 * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit b099d7
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit b099d7
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit b099d7
 *
Packit b099d7
 * Except as contained in this notice, the name of GROUPE BULL shall not be
Packit b099d7
 * used in advertising or otherwise to promote the sale, use or other dealings
Packit b099d7
 * in this Software without prior written authorization from GROUPE BULL.
Packit b099d7
 */
Packit b099d7
Packit b099d7
/*****************************************************************************\
Packit b099d7
* hashtab.c:                                                                  *
Packit b099d7
*                                                                             *
Packit b099d7
*  XPM library                                                                *
Packit b099d7
*                                                                             *
Packit b099d7
*  Developed by Arnaud Le Hors                                                *
Packit b099d7
*  this originaly comes from Colas Nahaboo as a part of Wool                  *
Packit b099d7
*                                                                             *
Packit b099d7
\*****************************************************************************/
Packit b099d7
Packit b099d7
#ifdef HAVE_CONFIG_H
Packit b099d7
#include <config.h>
Packit b099d7
#endif
Packit b099d7
Packit b099d7
Packit b099d7
#include "XpmI.h"
Packit b099d7
Packit b099d7
LFUNC(AtomMake, xpmHashAtom, (char *name, void *data));
Packit b099d7
LFUNC(HashTableGrows, int, (xpmHashTable * table));
Packit b099d7
Packit b099d7
static xpmHashAtom
Packit b099d7
AtomMake(name, data)			/* makes an atom */
Packit b099d7
    char *name;				/* WARNING: is just pointed to */
Packit b099d7
    void *data;
Packit b099d7
{
Packit b099d7
    xpmHashAtom object = (xpmHashAtom) XpmMalloc(sizeof(struct _xpmHashAtom));
Packit b099d7
Packit b099d7
    if (object) {
Packit b099d7
	object->name = name;
Packit b099d7
	object->data = data;
Packit b099d7
    }
Packit b099d7
    return object;
Packit b099d7
}
Packit b099d7
Packit b099d7
/************************\
Packit b099d7
* 			 *
Packit b099d7
*  hash table routines 	 *
Packit b099d7
* 			 *
Packit b099d7
\************************/
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Hash function definition:
Packit b099d7
 * HASH_FUNCTION: hash function, hash = hashcode, hp = pointer on char,
Packit b099d7
 *				 hash2 = temporary for hashcode.
Packit b099d7
 * INITIAL_TABLE_SIZE in slots
Packit b099d7
 * HASH_TABLE_GROWS how hash table grows.
Packit b099d7
 */
Packit b099d7
Packit b099d7
/* Mock lisp function */
Packit b099d7
#define HASH_FUNCTION 	  hash = (hash << 5) - hash + *hp++;
Packit b099d7
/* #define INITIAL_HASH_SIZE 2017 */
Packit b099d7
#define INITIAL_HASH_SIZE 256		/* should be enough for colors */
Packit b099d7
#define HASH_TABLE_GROWS  size = size * 2;
Packit b099d7
Packit b099d7
/* aho-sethi-ullman's HPJ (sizes should be primes)*/
Packit b099d7
#ifdef notdef
Packit b099d7
#define HASH_FUNCTION	hash <<= 4; hash += *hp++; \
Packit b099d7
    if(hash2 = hash & 0xf0000000) hash ^= (hash2 >> 24) ^ hash2;
Packit b099d7
#define INITIAL_HASH_SIZE 4095		/* should be 2^n - 1 */
Packit b099d7
#define HASH_TABLE_GROWS  size = size << 1 + 1;
Packit b099d7
#endif
Packit b099d7
Packit b099d7
/* GNU emacs function */
Packit b099d7
/*
Packit b099d7
#define HASH_FUNCTION 	  hash = (hash << 3) + (hash >> 28) + *hp++;
Packit b099d7
#define INITIAL_HASH_SIZE 2017
Packit b099d7
#define HASH_TABLE_GROWS  size = size * 2;
Packit b099d7
*/
Packit b099d7
Packit b099d7
/* end of hash functions */
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * The hash table is used to store atoms via their NAME:
Packit b099d7
 *
Packit b099d7
 * NAME --hash--> ATOM |--name--> "foo"
Packit b099d7
 *		       |--data--> any value which has to be stored
Packit b099d7
 *
Packit b099d7
 */
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * xpmHashSlot gives the slot (pointer to xpmHashAtom) of a name
Packit b099d7
 * (slot points to NULL if it is not defined)
Packit b099d7
 *
Packit b099d7
 */
Packit b099d7
Packit b099d7
xpmHashAtom *
Packit b099d7
xpmHashSlot(table, s)
Packit b099d7
    xpmHashTable *table;
Packit b099d7
    char *s;
Packit b099d7
{
Packit b099d7
    xpmHashAtom *atomTable = table->atomTable;
Packit b099d7
    unsigned int hash;
Packit b099d7
    xpmHashAtom *p;
Packit b099d7
    char *hp = s;
Packit b099d7
    char *ns;
Packit b099d7
Packit b099d7
    hash = 0;
Packit b099d7
    while (*hp) {			/* computes hash function */
Packit b099d7
	HASH_FUNCTION
Packit b099d7
    }
Packit b099d7
    p = atomTable + hash % table->size;
Packit b099d7
    while (*p) {
Packit b099d7
	ns = (*p)->name;
Packit b099d7
	if (ns[0] == s[0] && strcmp(ns, s) == 0)
Packit b099d7
	    break;
Packit b099d7
	p--;
Packit b099d7
	if (p < atomTable)
Packit b099d7
	    p = atomTable + table->size - 1;
Packit b099d7
    }
Packit b099d7
    return p;
Packit b099d7
}
Packit b099d7
Packit b099d7
static int
Packit b099d7
HashTableGrows(table)
Packit b099d7
    xpmHashTable *table;
Packit b099d7
{
Packit b099d7
    xpmHashAtom *atomTable = table->atomTable;
Packit b099d7
    unsigned int size = table->size;
Packit b099d7
    xpmHashAtom *t, *p;
Packit b099d7
    int i;
Packit b099d7
    unsigned int oldSize = size;
Packit b099d7
Packit b099d7
    t = atomTable;
Packit b099d7
    HASH_TABLE_GROWS
Packit b099d7
	table->size = size;
Packit b099d7
    table->limit = size / 3;
Packit b099d7
    if (size >= UINT_MAX / sizeof(*atomTable)) 
Packit b099d7
	return (XpmNoMemory);
Packit b099d7
    atomTable = (xpmHashAtom *) XpmMalloc(size * sizeof(*atomTable));
Packit b099d7
    if (!atomTable)
Packit b099d7
	return (XpmNoMemory);
Packit b099d7
    table->atomTable = atomTable;
Packit b099d7
    for (p = atomTable + size; p > atomTable;)
Packit b099d7
	*--p = NULL;
Packit b099d7
    for (i = 0, p = t; i < oldSize; i++, p++)
Packit b099d7
	if (*p) {
Packit b099d7
	    xpmHashAtom *ps = xpmHashSlot(table, (*p)->name);
Packit b099d7
Packit b099d7
	    *ps = *p;
Packit b099d7
	}
Packit b099d7
    XpmFree(t);
Packit b099d7
    return (XpmSuccess);
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * xpmHashIntern(table, name, data)
Packit b099d7
 * an xpmHashAtom is created if name doesn't exist, with the given data.
Packit b099d7
 */
Packit b099d7
Packit b099d7
int
Packit b099d7
xpmHashIntern(table, tag, data)
Packit b099d7
    xpmHashTable *table;
Packit b099d7
    char *tag;
Packit b099d7
    void *data;
Packit b099d7
{
Packit b099d7
    xpmHashAtom *slot;
Packit b099d7
Packit b099d7
    if (!*(slot = xpmHashSlot(table, tag))) {
Packit b099d7
	/* undefined, make a new atom with the given data */
Packit b099d7
	if (!(*slot = AtomMake(tag, data)))
Packit b099d7
	    return (XpmNoMemory);
Packit b099d7
	if (table->used >= table->limit) {
Packit b099d7
	    int ErrorStatus;
Packit b099d7
Packit b099d7
	    if ((ErrorStatus = HashTableGrows(table)) != XpmSuccess)
Packit b099d7
		return (ErrorStatus);
Packit b099d7
	    table->used++;
Packit b099d7
	    return (XpmSuccess);
Packit b099d7
	}
Packit b099d7
	table->used++;
Packit b099d7
    }
Packit b099d7
    return (XpmSuccess);
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *  must be called before allocating any atom
Packit b099d7
 */
Packit b099d7
Packit b099d7
int
Packit b099d7
xpmHashTableInit(table)
Packit b099d7
    xpmHashTable *table;
Packit b099d7
{
Packit b099d7
    xpmHashAtom *p;
Packit b099d7
    xpmHashAtom *atomTable;
Packit b099d7
Packit b099d7
    table->size = INITIAL_HASH_SIZE;
Packit b099d7
    table->limit = table->size / 3;
Packit b099d7
    table->used = 0;
Packit b099d7
    if (table->size >= UINT_MAX / sizeof(*atomTable))
Packit b099d7
	return (XpmNoMemory);
Packit b099d7
    atomTable = (xpmHashAtom *) XpmMalloc(table->size * sizeof(*atomTable));
Packit b099d7
    if (!atomTable)
Packit b099d7
	return (XpmNoMemory);
Packit b099d7
    for (p = atomTable + table->size; p > atomTable;)
Packit b099d7
	*--p = NULL;
Packit b099d7
    table->atomTable = atomTable;
Packit b099d7
    return (XpmSuccess);
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *   frees a hashtable and all the stored atoms
Packit b099d7
 */
Packit b099d7
Packit b099d7
void
Packit b099d7
xpmHashTableFree(table)
Packit b099d7
    xpmHashTable *table;
Packit b099d7
{
Packit b099d7
    xpmHashAtom *p;
Packit b099d7
    xpmHashAtom *atomTable = table->atomTable;
Packit b099d7
Packit b099d7
    if (!atomTable)
Packit b099d7
	return;
Packit b099d7
    for (p = atomTable + table->size; p > atomTable;)
Packit b099d7
	if (*--p)
Packit b099d7
	    XpmFree(*p);
Packit b099d7
    XpmFree(atomTable);
Packit b099d7
    table->atomTable = NULL;
Packit b099d7
}