|
Mixe for Privacy and Anonymity in the Internet
|
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
1.7.6.1