IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Hash_i_dh.c
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 #include "Hash_i_dh.h"
00044 #include "Parser_dh.h"
00045 #include "Mem_dh.h"
00046 
00047 #define DEFAULT_TABLE_SIZE 16
00048 
00049 static void rehash_private (Hash_i_dh h);
00050 
00051 
00052 /*--------------------------------------------------------------
00053  * hash functions (double hashing is used)
00054  *--------------------------------------------------------------*/
00055 #define HASH_1(k,size,idxOut)    \
00056          {  *idxOut = k % size;  }
00057 
00058 #define HASH_2(k,size,idxOut)      \
00059           {  \
00060             int r = k % (size-13); \
00061             r = (r % 2) ? r : r+1; \
00062             *idxOut = r;           \
00063           }
00064 
00065 
00066 /*--------------------------------------------------------------
00067  * class structure
00068  *--------------------------------------------------------------*/
00069 typedef struct _hash_i_node_private Hash_i_Record;
00070 
00071 struct _hash_i_node_private
00072 {
00073   int key;
00074   int mark;
00075   int data;
00076 };
00077 
00078 
00079 struct _hash_i_dh
00080 {
00081   int size;         /* total slots in table */
00082   int count;            /* number of items inserted in table */
00083   int curMark;          /* used by Reset */
00084   Hash_i_Record *data;
00085 };
00086 
00087 
00088 /*--------------------------------------------------------------
00089  * class methods follow
00090  *--------------------------------------------------------------*/
00091 
00092 #undef __FUNC__
00093 #define __FUNC__ "Hash_i_dhCreate"
00094 void
00095 Hash_i_dhCreate (Hash_i_dh * h, int sizeIN)
00096 {
00097   START_FUNC_DH int i, size;
00098   Hash_i_Record *tmp2;
00099   struct _hash_i_dh *tmp;
00100 
00101   size = DEFAULT_TABLE_SIZE;
00102   if (sizeIN == -1)
00103     {
00104       sizeIN = size = DEFAULT_TABLE_SIZE;
00105     }
00106   tmp = (struct _hash_i_dh *) MALLOC_DH (sizeof (struct _hash_i_dh));
00107   CHECK_V_ERROR;
00108   *h = tmp;
00109   tmp->size = 0;
00110   tmp->count = 0;
00111   tmp->curMark = 0;
00112   tmp->data = NULL;
00113 
00114   /*
00115      determine initial hash table size.  If this is too small,
00116      it will be dynamically enlarged as needed by Hash_i_dhInsert()
00117      See "double hashing," p. 255, "Algorithms," Cormen, et. al.
00118    */
00119   while (size < sizeIN)
00120     size *= 2;          /* want table size to be a power of 2: */
00121   /* rule-of-thumb: ensure there's at least 10% padding */
00122   if ((size - sizeIN) < (.1 * size))
00123     {
00124       size *= 2.0;
00125     }
00126   tmp->size = size;
00127 
00128 
00129   /* allocate and zero the hash table */
00130   tmp2 = tmp->data =
00131     (Hash_i_Record *) MALLOC_DH (size * sizeof (Hash_i_Record));
00132   CHECK_V_ERROR;
00133   for (i = 0; i < size; ++i)
00134     {
00135       tmp2[i].key = -1;
00136       tmp2[i].mark = -1;
00137       /* "tmp2[i].data" needn't be initialized */
00138     }
00139 
00140 END_FUNC_DH}
00141 
00142 
00143 #undef __FUNC__
00144 #define __FUNC__ "Hash_i_dhDestroy"
00145 void
00146 Hash_i_dhDestroy (Hash_i_dh h)
00147 {
00148   START_FUNC_DH if (h->data != NULL)
00149     {
00150       FREE_DH (h->data);
00151       CHECK_V_ERROR;
00152     }
00153   FREE_DH (h);
00154   CHECK_V_ERROR;
00155 END_FUNC_DH}
00156 
00157 #undef __FUNC__
00158 #define __FUNC__ "Hash_i_dhReset"
00159 void
00160 Hash_i_dhReset (Hash_i_dh h)
00161 {
00162   START_FUNC_DH h->count = 0;
00163   h->curMark += 1;
00164 END_FUNC_DH}
00165 
00166 
00167 #undef __FUNC__
00168 #define __FUNC__ "Hash_i_dhLookup"
00169 int
00170 Hash_i_dhLookup (Hash_i_dh h, int key)
00171 {
00172   START_FUNC_DH int idx, inc, i, start;
00173   int curMark = h->curMark;
00174   int size = h->size;
00175   int retval = -1;
00176   Hash_i_Record *data = h->data;
00177 
00178   HASH_1 (key, size, &start) HASH_2 (key, size, &inc)
00179 /*printf("Hash_i_dhLookup:: key: %i  tableSize: %i start: %i  inc: %i\n", key, size, start, inc);
00180 */
00181     for (i = 0; i < size; ++i)
00182     {
00183       idx = (start + i * inc) % size;
00184 
00185 /* printf("   idx= %i\n", idx); */
00186 
00187       if (data[idx].mark != curMark)
00188     {
00189       break;        /* key wasn't found */
00190     }
00191       else
00192     {
00193       if (data[idx].key == key)
00194         {
00195           retval = data[idx].data;
00196           break;
00197         }
00198     }
00199     }
00200 END_FUNC_VAL (retval)}
00201 
00202 
00203 #undef __FUNC__
00204 #define __FUNC__ "Hash_i_dhInsert"
00205 void
00206 Hash_i_dhInsert (Hash_i_dh h, int key, int dataIN)
00207 {
00208   START_FUNC_DH int i, idx, inc, start, size;
00209   int curMark = h->curMark;
00210   Hash_i_Record *data;
00211   bool success = false;
00212 
00213   if (dataIN < 0)
00214     {
00215       sprintf (msgBuf_dh, "data = %i must be >= 0", dataIN);
00216       SET_V_ERROR (msgBuf_dh);
00217     }
00218 
00219   /* enlarge table if necessary */
00220   if (h->count >= 0.9 * h->size)
00221     {
00222       rehash_private (h);
00223       CHECK_V_ERROR;
00224     }
00225 
00226   size = h->size;
00227   data = h->data;
00228   h->count += 1;        /* for this insertion */
00229 
00230   HASH_1 (key, size, &start) HASH_2 (key, size, &inc)
00231 /*printf("Hash_i_dhInsert::  tableSize= %i  start= %i  inc= %i\n", size, start, inc);
00232 */
00233     for (i = 0; i < size; ++i)
00234     {
00235       idx = (start + i * inc) % size;
00236 
00237 /* printf("   idx= %i\n", idx);
00238 */
00239 
00240       /* check for previous insertion */
00241       if (data[idx].mark == curMark && data[idx].key == key)
00242     {
00243       sprintf (msgBuf_dh, "key,data= <%i, %i> already inserted", key,
00244            dataIN);
00245       SET_V_ERROR (msgBuf_dh);
00246     }
00247 
00248       if (data[idx].mark < curMark)
00249     {
00250       data[idx].key = key;
00251       data[idx].mark = curMark;
00252       data[idx].data = dataIN;
00253       success = true;
00254       break;
00255     }
00256     }
00257 
00258   if (!success)
00259     {               /* should be impossible to be here, I think . . . */
00260       sprintf (msgBuf_dh, "Failed to insert key= %i, data= %i", key, dataIN);
00261     }
00262 END_FUNC_DH}
00263 
00264 
00265 #undef __FUNC__
00266 #define __FUNC__ "rehash_private"
00267 void
00268 rehash_private (Hash_i_dh h)
00269 {
00270   START_FUNC_DH
00271     int i,
00272     old_size = h->size, new_size = old_size * 2, oldCurMark = h->curMark;
00273   Hash_i_Record *oldData = h->data, *newData;
00274 
00275   sprintf (msgBuf_dh, "rehashing; old_size= %i, new_size= %i", old_size,
00276        new_size);
00277   SET_INFO (msgBuf_dh);
00278 
00279   /* allocate new data table, and install it in the Hash_i_dh object;
00280      essentially, we reinitialize the hash object.
00281    */
00282   newData = (Hash_i_Record *) MALLOC_DH (new_size * sizeof (Hash_i_Record));
00283   CHECK_V_ERROR;
00284   for (i = 0; i < new_size; ++i)
00285     {
00286       newData[i].key = -1;
00287       newData[i].mark = -1;
00288     }
00289   h->size = new_size;
00290   h->data = newData;
00291   h->count = 0;
00292   h->curMark = 0;
00293 
00294   for (i = h->count; i < new_size; ++i)
00295     {
00296       newData[i].key = -1;
00297       newData[i].mark = -1;
00298     }
00299 
00300   /* insert <key, data> pairs from old table to new table;
00301      wouldn't have been called) it's simplest to sweep through
00302      the old table.
00303    */
00304   for (i = 0; i < old_size; ++i)
00305     {
00306       if (oldData[i].mark == oldCurMark)
00307     {
00308       Hash_i_dhInsert (h, oldData[i].key, oldData[i].data);
00309       CHECK_V_ERROR;
00310     }
00311     }
00312 
00313   FREE_DH (oldData);
00314   CHECK_V_ERROR;
00315 END_FUNC_DH}
 All Classes Files Functions Variables Enumerations Friends