381 lines
7.3 KiB
C++
381 lines
7.3 KiB
C++
/*
|
|
* File: wb_hash.cc
|
|
* Purpose: Hash table implementation
|
|
* Author: Julian Smart
|
|
* Created: 1993
|
|
* Updated: August 1994
|
|
* Copyright: (c) 2004-2009 PLT Scheme Inc.
|
|
* Copyright: (c) 1993, AIAI, University of Edinburgh
|
|
*/
|
|
|
|
#pragma implementation "wx_hash.h"
|
|
|
|
#if defined(_MSC_VER)
|
|
# include "wx.h"
|
|
#else
|
|
# ifdef wx_xt
|
|
# define Uses_wxHashTable
|
|
# include "wx.h"
|
|
# else
|
|
# include "common.h"
|
|
# include "wx_list.h"
|
|
# include "wx_hash.h"
|
|
# include "wx_types.h"
|
|
# endif
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
wxHashTable::wxHashTable (int, int size)
|
|
: wxObject(WXGC_NO_CLEANUP)
|
|
{
|
|
int i;
|
|
wxList **ll;
|
|
|
|
__type = wxTYPE_HASH_TABLE;
|
|
n = size;
|
|
current_position = -1;
|
|
current_node = NULL;
|
|
|
|
ll = new WXGC_PTRS wxList *[size];
|
|
hash_table = ll;
|
|
for (i = 0; i < size; i++) {
|
|
hash_table[i] = NULL;
|
|
}
|
|
}
|
|
|
|
wxHashTable::~wxHashTable (void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < n; i++) {
|
|
if (hash_table[i]) {
|
|
wxList *l;
|
|
l = hash_table[i];
|
|
DELETE_OBJ l;
|
|
}
|
|
}
|
|
}
|
|
|
|
wxList *wxHashTable::GetList(int position, KeyType ktype, Bool makeit)
|
|
{
|
|
wxList *l;
|
|
|
|
l = hash_table[position];
|
|
|
|
if (!l) {
|
|
if (makeit) {
|
|
l = new WXGC_PTRS wxList(ktype, FALSE);
|
|
hash_table[position] = l;
|
|
}
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
void wxHashTable::Put(long key, wxObject * object)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key));
|
|
|
|
l->Append(key, object);
|
|
}
|
|
|
|
void wxHashTable::Put(const char *key, wxObject * object)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key), wxKEY_STRING);
|
|
|
|
l->Append(key, object);
|
|
}
|
|
|
|
wxObject *wxHashTable::Get(long key)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key), wxKEY_INTEGER, FALSE);
|
|
|
|
if (l) {
|
|
wxNode *node;
|
|
node = l->Find(key);
|
|
if (node)
|
|
return node->Data();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
wxObject *wxHashTable::Get(const char *key)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key), wxKEY_STRING, FALSE);
|
|
|
|
if (l) {
|
|
wxNode *node;
|
|
node = l->Find (key);
|
|
if (node)
|
|
return node->Data();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
wxObject *wxHashTable::Delete(long key)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key), wxKEY_INTEGER, FALSE);
|
|
|
|
if (l) {
|
|
wxNode *node;
|
|
node = l->Find(key);
|
|
if (node) {
|
|
wxObject *data;
|
|
data = node->Data();
|
|
l->DeleteNode(node);
|
|
return data;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
wxObject *wxHashTable::Delete(const char *key)
|
|
{
|
|
wxList *l;
|
|
|
|
l = GetList(MakeKey(key), wxKEY_STRING, FALSE);
|
|
|
|
if (l) {
|
|
wxNode *node;
|
|
node = l->Find(key);
|
|
if (node) {
|
|
wxObject *data;
|
|
data = node->Data();
|
|
l->DeleteNode(node);
|
|
return data;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int wxHashTable::MakeKey(const char *string)
|
|
{
|
|
long int_key = 0;
|
|
|
|
while (*string) {
|
|
int_key += (unsigned char) *string++;
|
|
}
|
|
|
|
if (int_key < 0)
|
|
int_key = -int_key;
|
|
|
|
return int_key % n;
|
|
}
|
|
|
|
int wxHashTable::MakeKey(long int_key)
|
|
{
|
|
if (int_key < 0)
|
|
int_key = -int_key;
|
|
|
|
return int_key % n;
|
|
}
|
|
|
|
void wxHashTable::BeginFind (void)
|
|
{
|
|
current_position = -1;
|
|
current_node = NULL;
|
|
}
|
|
|
|
wxNode *wxHashTable::Next (void)
|
|
{
|
|
wxNode *found = NULL;
|
|
Bool end = FALSE;
|
|
while (!end && !found) {
|
|
if (!current_node) {
|
|
current_position++;
|
|
if (current_position >= n) {
|
|
current_position = -1;
|
|
current_node = NULL;
|
|
end = TRUE;
|
|
} else {
|
|
wxList *l;
|
|
l = hash_table[current_position];
|
|
if (l) {
|
|
current_node = l->First();
|
|
found = current_node;
|
|
}
|
|
}
|
|
} else {
|
|
current_node = current_node->Next ();
|
|
found = current_node;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
void wxHashTable::DeleteContents (Bool flag)
|
|
{
|
|
int i;
|
|
for (i = 0; i < n; i++) {
|
|
if (hash_table[i]) {
|
|
wxList *l;
|
|
l = hash_table[i];
|
|
l->DeleteContents(flag);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxHashTable::Clear (void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < n; i++) {
|
|
if (hash_table[i]) {
|
|
wxList *l;
|
|
l = hash_table[i];
|
|
l->Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* This is a hash table implementation which does not lock the objects
|
|
from garbage collection. */
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
typedef long *nlWidgetRef;
|
|
# define nl_malloc_bucket_array(size) GC_malloc(size)
|
|
# define nlGET_WIDGET(x) (*(long *)(x))
|
|
# define nlGET_OBJECT(x) (((wxObject **)(x))[1])
|
|
# define nlALLOC_WIDGET(w) { long *p; p = (long *)GC_malloc_atomic(sizeof(long)); w = p; }
|
|
# define nlALLOC_OBJECT(o) { void *p; p = GC_malloc_weak_box(NULL, NULL, 0); o = (wxObject *)p; }
|
|
#else
|
|
# define nl_malloc_bucket_array(size) GC_malloc_atomic(size)
|
|
typedef long nlWidgetRef;
|
|
# define nlGET_WIDGET(x) x
|
|
# define nlGET_OBJECT(x) x
|
|
# define nlALLOC_WIDGET(w) /* empty */
|
|
# define nlALLOC_OBJECT(w) /* empty */
|
|
#endif
|
|
|
|
typedef struct Bucket {
|
|
nlWidgetRef widget;
|
|
wxObject *object;
|
|
} Bucket;
|
|
|
|
/* because widgets are likely to be word-aligned */
|
|
#define HASH(w) ((((unsigned long)w) >> 2) % numbuckets)
|
|
|
|
#define FILL_FACTOR 2 /* inverted max fraction of hash table implying reash */
|
|
|
|
wxNonlockingHashTable::wxNonlockingHashTable()
|
|
{
|
|
long i;
|
|
Bucket *bs;
|
|
|
|
numbuckets = 1001;
|
|
bs = (Bucket *)nl_malloc_bucket_array(sizeof(Bucket) * numbuckets);
|
|
buckets = bs;
|
|
for (i = 0; i < numbuckets; i++) {
|
|
buckets[i].widget = 0;
|
|
}
|
|
numwidgets = numused = 0;
|
|
}
|
|
|
|
wxNonlockingHashTable::~wxNonlockingHashTable()
|
|
{
|
|
}
|
|
|
|
void wxNonlockingHashTable::Put(long widget, wxObject *object)
|
|
{
|
|
long i;
|
|
|
|
if (FILL_FACTOR * numused >= numbuckets) {
|
|
/* Rehash */
|
|
Bucket *oldbuckets = buckets, *bs;
|
|
long oldnumbuckets = numbuckets;
|
|
|
|
if (FILL_FACTOR * numwidgets >= numbuckets)
|
|
numbuckets = (numbuckets * FILL_FACTOR) + 1;
|
|
/* else, just need to rehash after many deletions */
|
|
|
|
bs = (Bucket *)nl_malloc_bucket_array(sizeof(Bucket) * numbuckets);
|
|
buckets = bs;
|
|
for (i = 0; i < numbuckets; i++) {
|
|
buckets[i].widget = 0;
|
|
}
|
|
|
|
numwidgets = numused = 0;
|
|
for (i = 0; i < oldnumbuckets; i++) {
|
|
if (oldbuckets[i].widget && oldbuckets[i].object)
|
|
Put(nlGET_WIDGET(oldbuckets[i].widget), nlGET_OBJECT(oldbuckets[i].object));
|
|
}
|
|
}
|
|
|
|
i = HASH(widget);
|
|
while (buckets[i].widget && buckets[i].object
|
|
&& (nlGET_WIDGET(buckets[i].widget) != widget)) {
|
|
i = (i + 1) % numbuckets;
|
|
}
|
|
if (!buckets[i].widget)
|
|
numused++;
|
|
nlALLOC_WIDGET(buckets[i].widget);
|
|
nlGET_WIDGET(buckets[i].widget) = widget;
|
|
nlALLOC_OBJECT(buckets[i].object);
|
|
nlGET_OBJECT(buckets[i].object) = object;
|
|
numwidgets++;
|
|
}
|
|
|
|
wxObject *wxNonlockingHashTable::Get(long widget)
|
|
{
|
|
long i;
|
|
|
|
i = HASH(widget);
|
|
while (buckets[i].widget && (nlGET_WIDGET(buckets[i].widget) != widget)) {
|
|
i = (i + 1) % numbuckets;
|
|
}
|
|
|
|
if (buckets[i].widget
|
|
&& (nlGET_WIDGET(buckets[i].widget) == widget)
|
|
&& buckets[i].object) {
|
|
wxObject *r;
|
|
r = nlGET_OBJECT(buckets[i].object);
|
|
return r;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void wxNonlockingHashTable::Delete(long widget)
|
|
{
|
|
long i;
|
|
|
|
i = HASH(widget);
|
|
while (buckets[i].widget && (nlGET_WIDGET(buckets[i].widget) != widget)) {
|
|
i = (i + 1) % numbuckets;
|
|
}
|
|
|
|
if (buckets[i].widget && (nlGET_WIDGET(buckets[i].widget) == widget)) {
|
|
buckets[i].object = NULL;
|
|
--numwidgets;
|
|
/* Don't decrement numused, since the widget half is still set;
|
|
we should re-hash after enough deletions */
|
|
}
|
|
}
|
|
|
|
/* not particularly fast... */
|
|
void wxNonlockingHashTable::DeleteObject(wxObject *o)
|
|
{
|
|
long i;
|
|
|
|
for (i = 0; i < numbuckets; i++) {
|
|
if (buckets[i].widget && buckets[i].object && nlGET_OBJECT(buckets[i].object) == o)
|
|
Delete(nlGET_WIDGET(buckets[i].widget));
|
|
}
|
|
}
|
|
|