summaryrefslogtreecommitdiffstats
path: root/kpat/freecell-solver/fcs_hash.c
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitc90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch)
tree6d8391395bce9eaea4ad78958617edb20c6a7573 /kpat/freecell-solver/fcs_hash.c
downloadtdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.tar.gz
tdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegames@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kpat/freecell-solver/fcs_hash.c')
-rw-r--r--kpat/freecell-solver/fcs_hash.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/kpat/freecell-solver/fcs_hash.c b/kpat/freecell-solver/fcs_hash.c
new file mode 100644
index 00000000..fde7a03f
--- /dev/null
+++ b/kpat/freecell-solver/fcs_hash.c
@@ -0,0 +1,291 @@
+/*
+ * fcs_hash.c - an implementation of a simplistic (keys only) hash. This
+ * hash uses chaining and re-hashing and was found to be very fast. Not all
+ * of the functions of the hash ADT are implemented, but it is useful enough
+ * for Freecell Solver.
+ *
+ * Written by Shlomi Fish (shlomif@vipe.technion.ac.il), 2000
+ *
+ * This file is in the public domain (it's uncopyrighted).
+ */
+
+#include "fcs_config.h"
+
+#if (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INTERNAL_HASH) || (defined(INDIRECT_STACK_STATES) && (FCS_STACK_STORAGE == FCS_STACK_STORAGE_INTERNAL_HASH))
+
+#include <stdlib.h>
+#include <string.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "fcs_hash.h"
+
+#include "alloc.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+static void SFO_hash_rehash(SFO_hash_t * hash);
+
+
+
+SFO_hash_t * freecell_solver_hash_init(
+ SFO_hash_value_t wanted_size,
+ int (*compare_function)(const void * key1, const void * key2, void * context),
+ void * context
+ )
+{
+ int size;
+ SFO_hash_t * hash;
+
+ /* Find a prime number that is greater than the initial wanted size */
+ size = 256;
+ while (size < wanted_size)
+ {
+ size <<= 1;
+ }
+
+ hash = (SFO_hash_t *)malloc(sizeof(SFO_hash_t));
+
+ hash->size = size;
+ hash->size_bitmask = size-1;
+
+ hash->num_elems = 0;
+
+ /* Allocate a table of size entries */
+ hash->entries = (SFO_hash_symlink_t *)malloc(
+ sizeof(SFO_hash_symlink_t) * size
+ );
+
+ hash->compare_function = compare_function;
+ hash->context = context;
+
+ /* Initialize all the cells of the hash table to NULL, which indicate
+ that the cork of the linked list is right at the start */
+ memset(hash->entries, 0, sizeof(SFO_hash_symlink_t)*size);
+
+ hash->allocator = freecell_solver_compact_allocator_new();
+
+ return hash;
+}
+
+void * freecell_solver_hash_insert(
+ SFO_hash_t * hash,
+ void * key,
+ SFO_hash_value_t hash_value,
+ SFO_hash_value_t secondary_hash_value,
+ int optimize_for_caching
+ )
+{
+ int place;
+ SFO_hash_symlink_t * list;
+ SFO_hash_symlink_item_t * item, * last_item;
+
+ /* Get the index of the appropriate chain in the hash table */
+ place = hash_value & (hash->size_bitmask);
+
+ list = &(hash->entries[place]);
+ /* If first_item is non-existent */
+ if (list->first_item == NULL)
+ {
+ /* Allocate a first item with that key */
+ fcs_compact_alloc_into_var(item, hash->allocator, SFO_hash_symlink_item_t);
+ list->first_item = item;
+ item->next = NULL;
+ item->key = key;
+ item->hash_value = hash_value;
+ item->secondary_hash_value = secondary_hash_value;
+
+ goto rehash_check;
+ }
+
+ /* Initialize item to the chain's first_item */
+ item = list->first_item;
+ last_item = NULL;
+
+ while (item != NULL)
+ {
+ /*
+ We first compare the hash values, because it is faster than
+ comparing the entire data structure.
+
+ */
+ if (
+ (item->hash_value == hash_value) &&
+ (item->secondary_hash_value == secondary_hash_value) &&
+ (!(hash->compare_function(item->key, key, hash->context)))
+ )
+ {
+ if (optimize_for_caching)
+ {
+ /*
+ * Place the item in the beginning of the chain.
+ * If last_item == NULL it is already the first item so leave
+ * it alone
+ * */
+ if (last_item != NULL)
+ {
+ last_item->next = item->next;
+ item->next = list->first_item;
+ list->first_item = item;
+ }
+ }
+ return item->key;
+ }
+ /* Cache the item before the current in last_item */
+ last_item = item;
+ /* Move to the next item */
+ item = item->next;
+ }
+
+ if (optimize_for_caching)
+ {
+ /* Put the new element at the beginning of the list */
+ fcs_compact_alloc_into_var(item, hash->allocator, SFO_hash_symlink_item_t);
+ item->next = list->first_item;
+ item->key = key;
+ item->hash_value = hash_value;
+ list->first_item = item;
+ item->secondary_hash_value = secondary_hash_value;
+ }
+ else
+ {
+ /* Put the new element at the end of the list */
+ fcs_compact_alloc_into_var(item, hash->allocator, SFO_hash_symlink_item_t);
+ last_item->next = item;
+ item->next = NULL;
+ item->key = key;
+ item->hash_value = hash_value;
+ item->secondary_hash_value = secondary_hash_value;
+ }
+
+rehash_check:
+
+ hash->num_elems++;
+
+ if (hash->num_elems > ((hash->size*3)>>2))
+ {
+ SFO_hash_rehash(hash);
+ }
+
+ return NULL;
+}
+
+void freecell_solver_hash_free_with_callback(
+ SFO_hash_t * hash,
+ void (*function_ptr)(void * key, void * context)
+ )
+{
+ int i;
+ SFO_hash_symlink_item_t * item, * next_item;
+
+ for(i=0;i<hash->size;i++)
+ {
+ item = hash->entries[i].first_item;
+ while (item != NULL)
+ {
+ function_ptr(item->key, hash->context);
+ next_item = item->next;
+
+ item = next_item;
+ }
+ }
+
+ freecell_solver_hash_free(hash);
+}
+
+void freecell_solver_hash_free(
+ SFO_hash_t * hash
+ )
+{
+ freecell_solver_compact_allocator_finish(hash->allocator);
+
+ free(hash->entries);
+
+ free(hash);
+}
+
+
+/*
+ This function "rehashes" a hash. I.e: it increases the size of its
+ hash table, allowing for smaller chains, and faster lookup.
+
+ */
+static void SFO_hash_rehash(
+ SFO_hash_t * hash
+ )
+{
+ int old_size, new_size, new_size_bitmask;
+ int i;
+#if 0
+ SFO_hash_t * new_hash;
+#endif
+ SFO_hash_symlink_item_t * item, * next_item;
+ int place;
+ SFO_hash_symlink_t * new_entries;
+
+ old_size = hash->size;
+
+#if 0
+ /* Allocate a new hash with hash_init() */
+ new_hash = freecell_solver_hash_init_proto(
+ old_size * 2,
+ hash->compare_function,
+ hash->context
+ );
+#endif
+
+ old_size = hash->size;
+ new_size = old_size << 1;
+ new_size_bitmask = new_size - 1;
+
+ new_entries = calloc(new_size, sizeof(SFO_hash_symlink_t));
+
+ /* Copy the items to the new hash while not allocating them again */
+ for(i=0;i<old_size;i++)
+ {
+ item = hash->entries[i].first_item;
+ /* traverse the chain item by item */
+ while(item != NULL)
+ {
+ /* The place in the new hash table */
+ place = item->hash_value & new_size_bitmask;
+
+ /* Store the next item in the linked list in a safe place,
+ so we can retrieve it after the assignment */
+ next_item = item->next;
+ /* It is placed in front of the first element in the chain,
+ so it should link to it */
+ item->next = new_entries[place].first_item;
+
+ /* Make it the first item in its chain */
+ new_entries[place].first_item = item;
+
+ /* Move to the next item this one. */
+ item = next_item;
+ }
+ };
+
+ /* Free the entries of the old hash */
+ free(hash->entries);
+
+ /* Copy the new hash to the old one */
+#if 0
+ *hash = *new_hash;
+#endif
+ hash->entries = new_entries;
+ hash->size = new_size;
+ hash->size_bitmask = new_size_bitmask;
+}
+
+#else
+
+/* ANSI C doesn't allow empty compilation */
+static void freecell_solver_hash_c_dummy();
+
+#endif /* (FCS_STATE_STORAGE == FCS_STATE_STORAGE_INTERNAL_HASH) || defined(INDIRECT_STACK_STATES) */