hashtable_xsb.c

00001 /* File:      hashtable_xsb.c  -- a simple generic hash table ADT
00002 ** Author(s): Michael Kifer
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 2002
00006 ** 
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 ** 
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 ** 
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: hashtable_xsb.c,v 1.10 2005/12/12 18:44:52 dwarren Exp $
00022 ** 
00023 */
00024 
00025 
00026 #include "xsb_config.h"
00027 #include "xsb_debug.h"
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include "auxlry.h"
00034 #include "cell_xsb.h"
00035 #include "psc_xsb.h"
00036 #include "cinterf.h"
00037 #include "trie_internals.h"
00038 #include "macro_xsb.h"
00039 #include "error_xsb.h"
00040 
00041 #include "tr_utils.h"
00042 #include "debug_xsb.h"
00043 #include "flags_xsb.h"
00044 #include "memory_xsb.h"
00045 #include "heap_xsb.h"
00046 
00047 /*
00048   A simple hashtable.
00049   The first bucket is integrated into the hashtable and the overflow bullers
00050   are calloc()'ed. This gives good performance on insertion and search.
00051   When a collision happens on insertion, it requires a calloc().
00052   But collisions should be rare. Otherwise, should use a bigger table.
00053 */
00054 
00055 
00056 #define table_hash(val, length)    ((word)(val) % (length))
00057 
00058 #define get_top_bucket(htable,I) \
00059         ((xsbBucket *)(htable->table + (htable->bucket_size * I)))
00060 /* these two make sense only for top buckets, because we deallocate overflow
00061    buckets when they become free. */
00062 #define mark_bucket_free(bucket,size)   memset(bucket,(Cell)0,size)
00063 #define is_free_bucket(bucket)          (bucket->name == (Cell)0)
00064 
00065 static void init_hashtable(xsbHashTable *table);
00066 
00067 
00068 xsbBucket *search_bucket(Cell name,
00069                          xsbHashTable *table,
00070                          enum xsbHashSearchOp search_op)
00071 {
00072   xsbBucket *bucket, *prev;
00073 
00074   if (! table->initted) init_hashtable(table);
00075 
00076   prev = NULL;
00077   bucket = get_top_bucket(table,table_hash(name,table->length));
00078   while (bucket && bucket->name) {
00079     if (bucket->name == name) {
00080       if (search_op == hashtable_delete) {
00081         if (!prev) {
00082           /* if deleting a top bucket, copy the next bucket into the top one
00083              and delete that next bucket. If no next, then just nullify name */
00084           prev = bucket;
00085           bucket=bucket->next;
00086           if (bucket) {
00087             /* use memcpy() because client bucket might have extra fields */
00088             memcpy(prev, bucket, table->bucket_size);
00089             mem_dealloc(bucket,table->bucket_size,HASH_SPACE);
00090             //printf("dealloc bucket size: %d\n",table->bucket_size);
00091           } else {
00092             mark_bucket_free(prev,table->bucket_size);
00093             xsb_dbgmsg((LOG_HASHTABLE,
00094                        "SEARCH_BUCKET: Destroying storage handle for %s\n",
00095                        string_val(name)));
00096             xsb_dbgmsg((LOG_HASHTABLE, 
00097                        "SEARCH_BUCKET: Bucket nameptr is %p, next bucket %p\n",
00098                        prev->name, prev->next));
00099           }
00100         } else {
00101           /* Not top bucket: rearrange pointers & free space */
00102           prev->next = bucket->next;
00103           mem_dealloc(bucket,table->bucket_size,HASH_SPACE);
00104           //printf("dealloc bucket size: %d\n",table->bucket_size);
00105         }
00106         return NULL;
00107       } else
00108         return bucket;
00109     }
00110     prev = bucket;
00111     bucket = bucket->next;
00112   }
00113   /* not found */
00114   if (search_op != hashtable_insert) return NULL;
00115   /* else create new bucket */
00116   /* calloc nullifies the allocated space; CLIENTS RELY ON THIS */
00117   if (!bucket) { /* i.e., it is not a top bucket */
00118     bucket = (xsbBucket *)mem_calloc(1,table->bucket_size,HASH_SPACE);
00119     //printf("calloc bucket, size: %d\n",table->bucket_size);
00120     if (!bucket)
00121       xsb_exit("Out of Memory: Can't allocate hash bucket");
00122     prev->next = bucket;
00123     /* NOTE: not necessary to nullify bucket->next because of calloc() */
00124   }
00125   bucket->name = name;
00126   return bucket;
00127 }
00128 
00129 
00130 static void init_hashtable(xsbHashTable *table)
00131 {
00132   /* calloc zeroes the allocated space; clients rely on this */
00133   table->table = (byte *)mem_calloc(table->length,table->bucket_size,HASH_SPACE);
00134   //printf("calloc table, size: %d\n",table->length*table->bucket_size);
00135   if (!table->table)
00136     xsb_exit("Out of Memory: Can't create hash table");
00137   table->initted = TRUE;
00138 }
00139 
00140 void destroy_hashtable(xsbHashTable *table)
00141 {
00142   int i;
00143   xsbBucket *bucket, *next;
00144 
00145   table->initted = FALSE;
00146   for (i=0; i < table->length; i++) {
00147     /* follow pointers and free up buckets */
00148     bucket=get_top_bucket(table,i)->next;
00149     while (bucket != NULL) {
00150       next = bucket->next;
00151       mem_dealloc(bucket,table->bucket_size,HASH_SPACE);
00152       //printf("dealloc bucket size: %d\n",table->bucket_size);
00153       bucket = next;
00154     }
00155   }
00156   mem_dealloc(table->table,table->length*table->bucket_size,HASH_SPACE);
00157   //printf("dealloc table size: %d\n",table->length*table->bucket_size);
00158 
00159 }
00160 
00161 
00162 
00163 void show_table_state(xsbHashTable *table)
00164 {
00165   xsbBucket *bucket;
00166   int i;
00167 
00168   xsb_dbgmsg((LOG_DEBUG,"\nCell Status\tOverflow Count\n"));
00169   for (i=0; i < table->length; i++) {
00170     bucket = get_top_bucket(table,i);
00171     if (is_free_bucket(bucket)) {
00172       /* free cell */
00173       xsb_dbgmsg((LOG_DEBUG, "   ---\t\t   ---"));
00174     } else {
00175       int overflow_count=0;
00176 
00177       fprintf(stddbg, "  taken\t\t");
00178       bucket = bucket->next;
00179       while (bucket != NULL) {
00180         overflow_count++;
00181         bucket = bucket->next;
00182       }
00183       xsb_dbgmsg((LOG_DEBUG,"   %d", overflow_count));
00184     }
00185   }
00186 }
00187 
00188 #ifndef MULTI_THREAD
00189 // only handles the one hashtable.
00190 extern xsbHashTable bt_storage_hash_table;
00191 #endif
00192 
00193 void mark_hash_table_strings(CTXTdecl) {
00194   xsbBucket *bucket;
00195   int i;
00196   xsbHashTable *table;
00197 
00198   table = &bt_storage_hash_table;
00199   if (table->initted==TRUE) {
00200     for (i=0; i < table->length; i++) {
00201       bucket = get_top_bucket(table,i);
00202       if (!is_free_bucket(bucket)) {
00203         if (bucket->name && isstring(bucket->name)) {
00204           mark_string(string_val(bucket->name),"hashtable");
00205         }
00206         bucket = bucket->next;
00207         while (bucket != NULL) {
00208           if (bucket->name && isstring(bucket->name)) {
00209             mark_string(string_val(bucket->name),"hashtable-b");
00210           }
00211           bucket = bucket->next;
00212         }
00213       }
00214     }
00215   }
00216 }

Generated on Wed Jul 26 13:30:41 2006 for XSB by  doxygen 1.4.5