mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-18 08:51:45 -08:00
Dictionary implemented as a hash table Copied from Perforce Change: 20752 ServerID: perforce.ravenbrook.com
253 lines
5.3 KiB
C
253 lines
5.3 KiB
C
/* impl.h.table: A dictionary mapping a Word to a void*
|
|
* Copyright (C) 1997, 1999 Harlequin Group plc. All rights reserved.
|
|
*
|
|
* $HopeName$
|
|
*/
|
|
|
|
#include "table.h"
|
|
#include "mpmtypes.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include "mpstd.h"
|
|
#ifdef MPS_OS_SU
|
|
#include "ossu.h"
|
|
#endif
|
|
|
|
|
|
typedef unsigned long ulong;
|
|
|
|
|
|
#define TABLE_UNUSED ((Word)0x2AB7E040)
|
|
#define TABLE_DELETED ((Word)0x2AB7EDE7)
|
|
#define TABLE_ACTIVE ((Word)0x2AB7EAC2)
|
|
|
|
|
|
typedef struct TableEntryStruct *TableEntry;
|
|
typedef struct TableEntryStruct {
|
|
Word status;
|
|
Word key;
|
|
void *value;
|
|
} TableEntryStruct;
|
|
|
|
|
|
typedef struct TableStruct {
|
|
size_t length;
|
|
size_t count;
|
|
TableEntry array;
|
|
} TableStruct;
|
|
|
|
|
|
static ulong TableHash(Word key)
|
|
{
|
|
return key;
|
|
}
|
|
|
|
|
|
/* TableFind -- finds the entry for this key, or NULL */
|
|
|
|
static TableEntry TableFind(Table table, Word key, int skip_deleted)
|
|
{
|
|
ulong hash;
|
|
size_t i;
|
|
|
|
hash = TableHash(key) & (table->length - 1);
|
|
i = hash;
|
|
do {
|
|
switch (table->array[i].status) {
|
|
case TABLE_ACTIVE:
|
|
if (table->array[i].key == key)
|
|
return &table->array[i];
|
|
break;
|
|
case TABLE_DELETED:
|
|
if (!skip_deleted)
|
|
return &table->array[i];
|
|
break;
|
|
case TABLE_UNUSED:
|
|
return &table->array[i];
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
i = (i + (hash | 1)) & (table->length - 1);
|
|
} while(i != hash);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* TableGrow -- doubles the size of the table */
|
|
|
|
static Res TableGrow(Table table)
|
|
{
|
|
TableEntry oldArray, newArray;
|
|
size_t i, oldLength, newLength;
|
|
|
|
oldLength = table->length;
|
|
oldArray = table->array;
|
|
newLength = table->length * 2;
|
|
newArray = malloc(sizeof(TableEntryStruct) * newLength);
|
|
if(newArray == NULL) return ResMEMORY;
|
|
|
|
for(i = 0; i < newLength; ++i) {
|
|
newArray[i].key = 0;
|
|
newArray[i].value = NULL;
|
|
newArray[i].status = TABLE_UNUSED;
|
|
}
|
|
|
|
table->length = newLength;
|
|
table->array = newArray;
|
|
|
|
for(i = 0; i < oldLength; ++i) {
|
|
TableEntry entry;
|
|
assert(oldArray[i].status == TABLE_ACTIVE); /* should be full */
|
|
entry = TableFind(table, oldArray[i].key, 0 /* none deleted */);
|
|
assert(entry->status == TABLE_UNUSED); /* shouldn't be defined yet */
|
|
entry->key = oldArray[i].key;
|
|
entry->value = oldArray[i].value;
|
|
entry->status = TABLE_ACTIVE;
|
|
}
|
|
free(oldArray);
|
|
|
|
return ResOK;
|
|
}
|
|
|
|
|
|
/* TableCreate -- makes a new table */
|
|
|
|
extern Res TableCreate(Table *tableReturn, size_t length)
|
|
{
|
|
Table table;
|
|
size_t i;
|
|
|
|
assert(tableReturn != NULL);
|
|
|
|
table = malloc(sizeof(TableStruct));
|
|
if(table == NULL) goto failMallocTable;
|
|
table->length = length; table->count = 0;
|
|
table->array = malloc(sizeof(TableEntryStruct) * length);
|
|
if(table->array == NULL) goto failMallocArray;
|
|
for(i = 0; i < length; ++i) {
|
|
table->array[i].key = 0;
|
|
table->array[i].value = NULL;
|
|
table->array[i].status = TABLE_UNUSED;
|
|
}
|
|
|
|
*tableReturn = table;
|
|
return ResOK;
|
|
|
|
failMallocArray:
|
|
free(table);
|
|
failMallocTable:
|
|
return ResMEMORY;
|
|
}
|
|
|
|
|
|
extern void TableDestroy(Table table)
|
|
{
|
|
assert(table != NULL);
|
|
free(table->array);
|
|
free(table);
|
|
}
|
|
|
|
|
|
/* TableLookup -- look up */
|
|
|
|
extern void *TableLookup(Table table, Word key)
|
|
{
|
|
TableEntry entry = TableFind(table, key, 1 /* skip deleted */);
|
|
|
|
if((entry == NULL) ||
|
|
(entry->status != TABLE_ACTIVE))
|
|
return NULL;
|
|
|
|
return entry->value;
|
|
}
|
|
|
|
extern void *TableSlowLookup(Table table, Word key)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < table->length; i++)
|
|
if ((table->array[i].status == TABLE_ACTIVE) &&
|
|
(table->array[i].key == key))
|
|
return table->array[i].value;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* TableDefine -- add a new mapping */
|
|
|
|
extern Res TableDefine(Table table, Word key, void *value)
|
|
{
|
|
TableEntry entry = TableFind(table, key, 1 /* skip deletions */);
|
|
|
|
assert(entry == NULL || entry->status == TABLE_UNUSED);
|
|
|
|
if (entry == NULL) {
|
|
Res res;
|
|
entry = TableFind(table, key, 0 /* do not skip deletions */);
|
|
if (entry == NULL) {
|
|
/* table is full. Must grow the table to make room. */
|
|
res = TableGrow(table);
|
|
if(res != ResOK) return res;
|
|
entry = TableFind(table, key, 0 /* do not skip deletions */);
|
|
}
|
|
}
|
|
assert(entry != NULL && entry->status != TABLE_ACTIVE);
|
|
|
|
entry->status = TABLE_ACTIVE;
|
|
entry->key = key;
|
|
entry->value = value;
|
|
++table->count;
|
|
|
|
return ResOK;
|
|
}
|
|
|
|
|
|
/* TableRedefine -- redefine an existing mapping */
|
|
|
|
extern Res TableRedefine(Table table, Word key, void *value)
|
|
{
|
|
TableEntry entry = TableFind(table, key, 1 /* skip deletions */);
|
|
|
|
assert(entry != NULL);
|
|
assert(entry->status == TABLE_ACTIVE);
|
|
assert(entry->key == key);
|
|
entry->value = value;
|
|
return ResOK;
|
|
}
|
|
|
|
|
|
/* TableRemove -- remove a mapping */
|
|
|
|
extern Res TableRemove(Table table, Word key)
|
|
{
|
|
TableEntry entry = TableFind(table, key, 1);
|
|
if (entry == NULL || entry->status != TABLE_ACTIVE)
|
|
return ResFAIL;
|
|
|
|
entry->status = TABLE_DELETED;
|
|
--table->count;
|
|
return ResOK;
|
|
}
|
|
|
|
|
|
/* TableApply -- apply a function to all the mappings */
|
|
|
|
extern void TableApply(Table table, void(*fun)(Word key, void*value))
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < table->length; i++)
|
|
if (table->array[i].status == TABLE_ACTIVE)
|
|
(*fun)(table->array[i].key, table->array[i].value);
|
|
}
|
|
|
|
|
|
/* TableCount -- count the number of mappings in the table */
|
|
|
|
extern size_t TableCount(Table table)
|
|
{
|
|
return table->count;
|
|
}
|