|
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 |
}
|