You've already forked libspectrum
mirror of
https://git.code.sf.net/p/fuse-emulator/libspectrum
synced 2025-08-04 19:02:09 +03:00
378 lines
8.6 KiB
C
378 lines
8.6 KiB
C
/* ghash.c: Minimal replacement for GHashTable
|
|
|
|
This code taken almost verbatim from glib 2.4.0's glib/ghash.c
|
|
Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
|
file for a list of people on the GLib Team. See the ChangeLog
|
|
files for a list of changes. These files are distributed with GLib
|
|
at ftp://ftp.gtk.org/pub/gtk/.
|
|
|
|
Modified by Philip Kendall 2004-2011.
|
|
|
|
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.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
Philip Kendall <philip-fuse@shadowmagic.org.uk>
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifndef HAVE_LIB_GLIB /* Use this iff we're not using the
|
|
`proper' glib */
|
|
#include <string.h>
|
|
|
|
#include "internals.h"
|
|
|
|
#define HASH_TABLE_SIZE 241
|
|
|
|
typedef struct _GHashNode GHashNode;
|
|
|
|
struct _GHashNode
|
|
{
|
|
gpointer key;
|
|
gpointer value;
|
|
GHashNode *next;
|
|
};
|
|
|
|
struct _GHashTable
|
|
{
|
|
gint nnodes;
|
|
GHashNode **nodes;
|
|
GHashFunc hash_func;
|
|
GCompareFunc key_equal_func;
|
|
GDestroyNotify key_destroy_func;
|
|
GDestroyNotify value_destroy_func;
|
|
};
|
|
|
|
static GHashNode *node_free_list = NULL;
|
|
static GHashNode *node_allocated_list = NULL;
|
|
|
|
#ifdef HAVE_STDATOMIC_H
|
|
|
|
static atomic_char atomic_locker = ATOMIC_VAR_INIT(0);
|
|
|
|
#define lock() atomic_lock( &atomic_locker )
|
|
#define unlock() atomic_unlock( &atomic_locker )
|
|
|
|
#else /* #ifdef HAVE_STDATOMIC_H */
|
|
|
|
#define lock()
|
|
#define unlock()
|
|
|
|
#endif /* #ifdef HAVE_STDATOMIC_H */
|
|
|
|
static guint
|
|
g_direct_hash (gconstpointer v)
|
|
{
|
|
return GPOINTER_TO_UINT (v);
|
|
}
|
|
|
|
GHashTable*
|
|
g_hash_table_new (GHashFunc hash_func,
|
|
GCompareFunc key_equal_func)
|
|
{
|
|
return g_hash_table_new_full( hash_func, key_equal_func, NULL, NULL );
|
|
}
|
|
|
|
GHashTable*
|
|
g_hash_table_new_full (GHashFunc hash_func,
|
|
GCompareFunc key_equal_func,
|
|
GDestroyNotify key_destroy_func,
|
|
GDestroyNotify value_destroy_func)
|
|
{
|
|
GHashTable *hash_table;
|
|
guint i;
|
|
|
|
hash_table = libspectrum_malloc (sizeof (GHashTable));
|
|
|
|
hash_table->nnodes = 0;
|
|
hash_table->hash_func = hash_func? hash_func : g_direct_hash;
|
|
hash_table->key_equal_func = key_equal_func;
|
|
hash_table->key_destroy_func = key_destroy_func;
|
|
hash_table->value_destroy_func = value_destroy_func;
|
|
hash_table->nodes = libspectrum_malloc (HASH_TABLE_SIZE * sizeof (GHashNode*));
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
hash_table->nodes[i] = NULL;
|
|
|
|
return hash_table;
|
|
}
|
|
|
|
static void
|
|
g_hash_nodes_destroy (GHashNode *hash_node,
|
|
GFreeFunc key_destroy_func,
|
|
GFreeFunc value_destroy_func)
|
|
{
|
|
if (hash_node)
|
|
{
|
|
GHashNode *node = hash_node;
|
|
|
|
while (node->next) {
|
|
if (key_destroy_func)
|
|
key_destroy_func (node->key);
|
|
if (value_destroy_func)
|
|
value_destroy_func (node->value);
|
|
|
|
node = node->next;
|
|
}
|
|
|
|
if (key_destroy_func)
|
|
key_destroy_func (node->key);
|
|
if (value_destroy_func)
|
|
value_destroy_func (node->value);
|
|
|
|
lock();
|
|
node->next = node_free_list;
|
|
node_free_list = hash_node;
|
|
unlock();
|
|
}
|
|
}
|
|
|
|
void
|
|
g_hash_table_destroy (GHashTable *hash_table)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
g_hash_nodes_destroy (hash_table->nodes[i],
|
|
hash_table->key_destroy_func,
|
|
hash_table->value_destroy_func);
|
|
|
|
libspectrum_free (hash_table->nodes);
|
|
libspectrum_free (hash_table);
|
|
}
|
|
|
|
static GHashNode**
|
|
g_hash_table_lookup_node (GHashTable *hash_table,
|
|
gconstpointer key)
|
|
{
|
|
GHashNode **node;
|
|
|
|
node = &hash_table->nodes
|
|
[(* hash_table->hash_func) (key) % HASH_TABLE_SIZE];
|
|
|
|
while( *node ) {
|
|
if( hash_table->key_equal_func ) {
|
|
if( hash_table->key_equal_func( (*node)->key, key ) ) break;
|
|
} else if( (*node)->key == key ) {
|
|
break;
|
|
}
|
|
|
|
node = &(*node)->next;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
gpointer
|
|
g_hash_table_lookup (GHashTable *hash_table,
|
|
gconstpointer key)
|
|
{
|
|
GHashNode *node;
|
|
|
|
node = *g_hash_table_lookup_node (hash_table, key);
|
|
|
|
return node ? node->value : NULL;
|
|
}
|
|
|
|
static GHashNode*
|
|
g_hash_node_new (gpointer key,
|
|
gpointer value)
|
|
{
|
|
GHashNode *hash_node;
|
|
guint i;
|
|
|
|
lock();
|
|
if (!node_free_list)
|
|
{
|
|
node_free_list = libspectrum_malloc (1024 * sizeof (GHashNode));
|
|
node_allocated_list = node_free_list;
|
|
|
|
for(i = 0; i < 1023; i++ )
|
|
node_free_list[i].next = &node_free_list[i+1];
|
|
node_free_list[1023].next = NULL;
|
|
}
|
|
|
|
|
|
hash_node = node_free_list;
|
|
node_free_list = node_free_list->next;
|
|
unlock();
|
|
|
|
hash_node->key = key;
|
|
hash_node->value = value;
|
|
hash_node->next = NULL;
|
|
|
|
return hash_node;
|
|
}
|
|
|
|
void
|
|
g_hash_table_insert (GHashTable *hash_table,
|
|
gpointer key,
|
|
gpointer value)
|
|
{
|
|
GHashNode **node;
|
|
|
|
node = g_hash_table_lookup_node (hash_table, key);
|
|
|
|
if (*node)
|
|
{
|
|
/* free the passed key */
|
|
if (hash_table->key_destroy_func)
|
|
hash_table->key_destroy_func (key);
|
|
|
|
if (hash_table->value_destroy_func)
|
|
hash_table->value_destroy_func ((*node)->value);
|
|
|
|
(*node)->value = value;
|
|
}
|
|
else
|
|
{
|
|
*node = g_hash_node_new (key, value);
|
|
hash_table->nnodes++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
g_hash_node_destroy (GHashNode *hash_node,
|
|
GDestroyNotify key_destroy_func,
|
|
GDestroyNotify value_destroy_func)
|
|
{
|
|
if (key_destroy_func)
|
|
key_destroy_func (hash_node->key);
|
|
if (value_destroy_func)
|
|
value_destroy_func (hash_node->value);
|
|
|
|
lock();
|
|
hash_node->next = node_free_list;
|
|
node_free_list = hash_node;
|
|
unlock();
|
|
}
|
|
|
|
guint
|
|
g_hash_table_foreach_remove (GHashTable *hash_table,
|
|
GHRFunc func,
|
|
gpointer user_data)
|
|
{
|
|
GHashNode *node, *prev;
|
|
guint i;
|
|
guint deleted = 0;
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
{
|
|
restart:
|
|
|
|
prev = NULL;
|
|
|
|
for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
|
|
{
|
|
if ((* func) (node->key, node->value, user_data))
|
|
{
|
|
deleted += 1;
|
|
|
|
hash_table->nnodes -= 1;
|
|
|
|
if (prev)
|
|
{
|
|
prev->next = node->next;
|
|
g_hash_node_destroy (node,
|
|
hash_table->key_destroy_func,
|
|
hash_table->value_destroy_func);
|
|
node = prev;
|
|
}
|
|
else
|
|
{
|
|
hash_table->nodes[i] = node->next;
|
|
g_hash_node_destroy (node,
|
|
hash_table->key_destroy_func,
|
|
hash_table->value_destroy_func);
|
|
goto restart;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return deleted;
|
|
}
|
|
|
|
void
|
|
g_hash_table_foreach (GHashTable *hash_table,
|
|
GHFunc func,
|
|
gpointer user_data)
|
|
{
|
|
GHashNode *node;
|
|
gint i;
|
|
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++)
|
|
for (node = hash_table->nodes[i]; node; node = node->next)
|
|
(* func) (node->key, node->value, user_data);
|
|
}
|
|
|
|
guint
|
|
g_hash_table_size (GHashTable *hash_table)
|
|
{
|
|
return hash_table->nnodes;
|
|
}
|
|
|
|
guint
|
|
g_int_hash (gconstpointer v)
|
|
{
|
|
return *(const gint*) v;
|
|
}
|
|
|
|
gboolean
|
|
g_int_equal (gconstpointer v1,
|
|
gconstpointer v2)
|
|
{
|
|
return *((const gint*) v1) == *((const gint*) v2);
|
|
}
|
|
|
|
guint
|
|
g_str_hash (gconstpointer v)
|
|
{
|
|
/* 31 bit hash function */
|
|
const signed char *p = v;
|
|
libspectrum_dword h = *p;
|
|
|
|
if (h)
|
|
for (p += 1; *p != '\0'; p++)
|
|
h = (h << 5) - h + *p;
|
|
|
|
return h;
|
|
}
|
|
|
|
gboolean
|
|
g_str_equal (gconstpointer v1,
|
|
gconstpointer v2)
|
|
{
|
|
const gchar *string1 = v1;
|
|
const gchar *string2 = v2;
|
|
|
|
return strcmp (string1, string2) == 0;
|
|
}
|
|
|
|
void
|
|
libspectrum_hashtable_cleanup( void )
|
|
{
|
|
lock();
|
|
libspectrum_free( node_allocated_list );
|
|
node_allocated_list = NULL;
|
|
node_free_list = NULL;
|
|
unlock();
|
|
}
|
|
#endif /* #ifndef HAVE_LIB_GLIB */
|