Mixe for Privacy and Anonymity in the Internet
Hashtable.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000-2007, The JAP-Team All rights reserved.
00003 Redistribution and use in source and binary forms, with or without
00004 modification, are permitted provided that the following conditions are
00005 met:
00006  
00007 - Redistributions of source code must retain the above copyright
00008 notice, this list of conditions and the following disclaimer.
00009  
00010 - Redistributions in binary form must reproduce the above
00011 copyright notice, this list of conditions and the following
00012 disclaimer in the documentation and/or other materials provided
00013 with the distribution.
00014  
00015 - Neither the name of the University of Technology Dresden,
00016 Germany nor the names of its contributors may be used to endorse
00017 or promote products derived from this software without specific
00018 prior written permission.
00019  
00020  
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00024 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
00025 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00027 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 
00032 */
00033 
00034 #include "StdAfx.h"
00035 
00036 #include "Hashtable.hpp"
00037 #include "CAMsg.hpp"
00038 #include "CAUtil.hpp"
00039 
00040 // Every entry in the hashtable is embedded in this structure
00041 
00042 struct Entry
00043 {
00044   struct Entry *e_Next;
00045   void   *e_Key;
00046   void   *e_Value;
00047 };
00048 
00049 
00050 
00051 /************************** Hashtable **************************/
00052 // #pragma mark -
00053 
00054 
00055 CAMutex *Hashtable::getMutex()
00056 {
00057   return m_pMutex;
00058 }
00059 
00060 
00061 /* Hashtable - a general purpose hash table
00062  * Erzeugt einen neuen Hashtable nach den Vorgaben des
00063  *  Benutzers.
00064  *
00065  *  @param capacity die Anfangskapazitt des Hashtables. Sie wird zwar bei
00066  *    Bedarf vergroessert, aber das kann dann etwas laenger dauern, da der Hashtable
00067  *    dann komplett neu aufgebaut werden muss Voreingestellt sind 100 Eintrge.
00068  *  @param loadFactor die gewueschte maximale Auslastung des Hashtables.
00069  *    Bei kleinen Werten muss der Hashtable haeufiger neu aufgebaut werden und belegt
00070  *    mehr Speicher, ist aber schnell. Bei groessen Werten wird das Beschreiben und
00071  *    Auslesen langsamer. Voreingestellt ist 0.75f.
00072  * 
00073 **/
00074 Hashtable::Hashtable(UINT32 (*hashFunc)(void *), SINT32 (*compareFunc)(void *,void *), SINT32 capacity, float loadFactor)
00075 {
00076   m_pMutex = new CAMutex();
00077   
00078   if (capacity < 0 || loadFactor <= 0)
00079   {
00080     return;
00081   }
00082 
00083   if (!capacity)
00084   {
00085     capacity = 1;
00086   } 
00087   
00088   m_table = new Entry*[capacity];
00089   for (SINT32 i = 0; i < capacity; i++)
00090   {
00091     m_table[i] = NULL;
00092   }
00093   
00094   m_threshold = (UINT32)(capacity * loadFactor);
00095   m_modCount = 0;
00096   m_count = 0;
00097   m_loadFactor = loadFactor;
00098   m_capacity = capacity;
00099 
00100   //m_hashFunc = (UINT32 (*)(void *))stringHash;
00101   m_hashFunc = hashFunc;
00102   //m_compareFunc = (SINT32 (*)(void *,void *))stringCompare;
00103   m_compareFunc = compareFunc;
00104 }
00105 
00106 
00107 Hashtable::~Hashtable()
00108 {
00109   m_pMutex->lock();
00110   
00111   for(SINT32 index = 0; index < m_capacity; index++)
00112   {
00113     struct Entry *e,*next;
00114 
00115     for(e = m_table[index]; e; e = next)
00116     {
00117       next = e->e_Next;
00118       delete e;
00119       e = NULL;
00120     }
00121     m_table[index] = NULL;
00122   }
00123   delete m_table;
00124   m_table = NULL;
00125   m_capacity = 0;
00126   m_count = 0;
00127   m_threshold = 0;
00128   m_loadFactor = 0;
00129   m_modCount = 0;
00130   m_hashFunc = NULL;
00131   m_compareFunc = NULL;
00132   
00133   m_pMutex->unlock();
00134   
00135   delete m_pMutex;
00136   m_pMutex = NULL;
00137 }
00138 
00139 
00140 
00141 
00147 bool Hashtable::isEmpty()
00148 {
00149   return m_count == 0;
00150 }
00151 
00152 
00159 bool Hashtable::containsKey(void *key)
00160 {
00161   return getHashEntry(key) ? true : false;
00162 }
00163 
00164 
00171 void *Hashtable::getValue(void *key)
00172 {   
00173   struct Entry *e = getHashEntry(key);
00174 
00175   return e ? e->e_Value : NULL;
00176 }
00177 
00178 
00192 void* Hashtable::put(void *key, void *value)
00193 {
00194   //CAMsg::printMsg(LOG_INFO, "Hashtable: Putting key.\n");
00195   
00196   if (!key || !value || !m_table)
00197   {
00198     return NULL;
00199   }
00200   
00201   struct Entry *oldEntry = NULL;
00202   struct Entry *newEntry = NULL;
00203   UINT32 hash = m_hashFunc(key);
00204   UINT32 index = hash % m_capacity;
00205   
00206   m_count++;
00207   if (m_count >= m_threshold)
00208   {   
00209     rehash();
00210   }
00211   
00212   index = hash % m_capacity;
00213   
00214   newEntry = new Entry;
00215   newEntry->e_Key = key;
00216   newEntry->e_Value = value;
00217   newEntry->e_Next = NULL;
00218   
00219   oldEntry = m_table[index];
00220   if (!oldEntry)
00221   {
00222     m_table[index] = newEntry;
00223   }
00224   else
00225   {
00226     struct Entry *prevEntry = NULL;
00227     for(; oldEntry; oldEntry = oldEntry->e_Next)
00228     {     
00229       if (m_hashFunc(oldEntry->e_Key) == hash && !m_compareFunc(oldEntry->e_Key,key))
00230       {
00231         // found the same entry
00232         newEntry->e_Next = oldEntry->e_Next;
00233         break;
00234       }
00235       prevEntry = oldEntry;
00236     }
00237     if (prevEntry)
00238     {
00239       prevEntry->e_Next = newEntry;
00240     }
00241     else
00242     {
00243       m_table[index] = newEntry;
00244     }
00245   }
00246   
00247   return oldEntry;
00248 }
00249 
00250 
00261 void *Hashtable::remove(void *key)
00262 {
00263   //CAMsg::printMsg(LOG_INFO, "Hashtable: Removing key.\n");
00264   
00265   if (!key || !m_table)
00266   {
00267     return NULL;
00268   }
00269   
00270   struct Entry *e,*prev;
00271   UINT32 hash = m_hashFunc(key);
00272   
00273   for(e = m_table[hash % m_capacity], prev = NULL; e; e = e->e_Next)
00274   {     
00275     if (m_hashFunc(e->e_Key) == hash && !m_compareFunc(e->e_Key,key))
00276     {
00277       void *value;
00278 
00279       //m_modCount++;
00280       if (prev)
00281       {
00282         prev->e_Next = e->e_Next;
00283       }
00284       else
00285       {
00286         m_table[hash % m_capacity] = e->e_Next;
00287       }
00288       
00289       m_count--;
00290       value = e->e_Value;
00291       e->e_Value = NULL;
00292       e->e_Key = NULL;
00293       e->e_Next = NULL;
00294       delete e;
00295       e = NULL;
00296 
00297       return value;
00298     }
00299     prev = e;
00300   }
00301   
00302   return NULL;
00303 }
00304 
00305 
00306 void Hashtable::clear(SINT8 keyMode,SINT8 valueMode)
00307 { 
00308   if (!m_table)
00309   {
00310     return;
00311   }
00312   
00313   //CAMsg::printMsg(LOG_INFO, "Hashtable: Clearing...\n");
00314 
00315   for(SINT32 index = 0; index < m_capacity; index++)
00316   {
00317     struct Entry *e,*next;
00318 
00319     for(e = m_table[index]; e; e = next)
00320     {
00321       switch(keyMode)
00322       {
00323         case HASH_EMPTY_DELETE:
00324           if (e->e_Key)
00325           {
00326             delete e->e_Key;
00327             e->e_Key = NULL;
00328           }
00329           break;
00330 //        case HASH_EMPTY_FREE:
00331 //          free(e->e_Key);
00332         default:
00333           e->e_Key = NULL;    
00334       }
00335       switch(valueMode)
00336       {
00337         case HASH_EMPTY_DELETE:
00338           if (e->e_Value)
00339           {
00340             delete e->e_Value;
00341             e->e_Value = NULL;
00342           }
00343           break;
00344 //        case HASH_EMPTY_FREE:
00345 //          free(e->e_Value);
00346         default:
00347           e->e_Value = NULL;
00348       }
00349       next = e->e_Next;
00350       delete e;
00351       e = NULL;
00352     }
00353     m_table[index] = NULL;
00354   }
00355   m_count = 0;
00356   
00357   //CAMsg::printMsg(LOG_INFO, "Hashtable: Has been cleared!\n");
00358 }
00359 
00360 UINT32 Hashtable::getSize()
00361 {
00362   return m_count;
00363 }
00364 
00365 UINT32 Hashtable::getCapacity()
00366 {
00367   return m_capacity;
00368 }
00369 
00370 
00376 bool Hashtable::rehash()
00377 {
00378   if (!m_table)
00379   {
00380     return false;
00381   }
00382   
00383   CAMsg::printMsg(LOG_INFO, "Hashtable: Rehashing.\n");
00384   
00385   UINT32 (*hashCode)(void *) = m_hashFunc;
00386   struct Entry **oldtable = m_table,**newtable;
00387   SINT32 oldCapacity = m_capacity;
00388   UINT32 newCapacity;
00389 
00390   newCapacity = oldCapacity * 2 + 1;
00391   newtable = new Entry*[newCapacity];
00392   for (UINT32 i = 0; i < newCapacity; i++)
00393   {
00394     newtable[i] = NULL;
00395   }
00396 
00397   m_modCount++;
00398   if (m_modCount > 10)
00399   {
00400     CAMsg::printMsg(LOG_INFO, "Hashtable: Too many rehash operations! Please adapt hashtable capacity to at least %d.\n", newCapacity);
00401   }
00402   
00403   m_threshold = (UINT32)(newCapacity * m_loadFactor);
00404   m_table = newtable;
00405   m_capacity = newCapacity;
00406 
00407   for(SINT32 i = 0; i < oldCapacity; i++)
00408   {
00409     struct Entry *nextEntry, *e = NULL;
00410     UINT32 index;
00411     
00412     for (nextEntry = oldtable[i]; nextEntry;)
00413     {
00414       e = nextEntry;  
00415       // save the previous next entry, as it will be deleted later
00416       nextEntry = nextEntry->e_Next;
00417             
00418       index = hashCode(e->e_Key) % newCapacity;
00419       /* If there has been another entry before, replace it.
00420        * Delete the previous next entry in the same step.
00421        */
00422       e->e_Next = newtable[index]; 
00423       newtable[index] = e;
00424     }
00425   }
00426   delete oldtable;
00427   oldtable = NULL;
00428   
00429   CAMsg::printMsg(LOG_INFO, "Hashtable: Rehashing complete.\n");
00430   
00431   return true;
00432 }
00433 
00434 
00442 struct Entry *Hashtable::getHashEntry(void *key)
00443 { 
00444   if (!key || !m_table)
00445   {
00446     return NULL;
00447   }
00448   
00449   struct Entry *e;
00450   UINT32 hash = m_hashFunc(key);
00451   
00452   for(e = m_table[hash % m_capacity]; e; e = e->e_Next)
00453   {   
00454     if (m_hashFunc(e->e_Key) == hash && !m_compareFunc(e->e_Key,key))
00455     {
00456       return e;
00457     }
00458   }
00459   
00460   return NULL;
00461 }
00462