Mixe for Privacy and Anonymity in the Internet
Hashtable.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2000-2007, The JAP-Team All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are
5 met:
6 
7 - Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 
10 - Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14 
15 - Neither the name of the University of Technology Dresden,
16 Germany nor the names of its contributors may be used to endorse
17 or promote products derived from this software without specific
18 prior written permission.
19 
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
32 */
33 
34 #include "StdAfx.h"
35 #ifdef PAYMENT
36 #include "Hashtable.hpp"
37 #include "CAMsg.hpp"
38 #include "CAUtil.hpp"
39 
40 // Every entry in the hashtable is embedded in this structure
41 
42 struct Entry
43 {
44  struct Entry *e_Next;
45  void *e_Key;
46  void *e_Value;
47 };
48 
49 
50 
51 /************************** Hashtable **************************/
52 // #pragma mark -
53 
54 
55 CAMutex *Hashtable::getMutex()
56 {
57  return m_pMutex;
58 }
59 
60 
61 /* Hashtable - a general purpose hash table
62  * Erzeugt einen neuen Hashtable nach den Vorgaben des
63  * Benutzers.
64  *
65  * @param capacity die Anfangskapazitt des Hashtables. Sie wird zwar bei
66  * Bedarf vergroessert, aber das kann dann etwas laenger dauern, da der Hashtable
67  * dann komplett neu aufgebaut werden muss Voreingestellt sind 100 Eintrge.
68  * @param loadFactor die gewueschte maximale Auslastung des Hashtables.
69  * Bei kleinen Werten muss der Hashtable haeufiger neu aufgebaut werden und belegt
70  * mehr Speicher, ist aber schnell. Bei groessen Werten wird das Beschreiben und
71  * Auslesen langsamer. Voreingestellt ist 0.75f.
72  *
73 **/
74 Hashtable::Hashtable(UINT32 (*hashFunc)(void *), SINT32 (*compareFunc)(void *,void *), SINT32 capacity, float loadFactor)
75 {
76  m_pMutex = new CAMutex();
77 
78  if (capacity < 0 || loadFactor <= 0)
79  {
80  return;
81  }
82 
83  if (!capacity)
84  {
85  capacity = 1;
86  }
87 
88  m_table = new Entry*[capacity];
89  for (SINT32 i = 0; i < capacity; i++)
90  {
91  m_table[i] = NULL;
92  }
93 
94  m_threshold = (UINT32)(capacity * loadFactor);
95  m_modCount = 0;
96  m_count = 0;
97  m_loadFactor = loadFactor;
98  m_capacity = capacity;
99 
100  //m_hashFunc = (UINT32 (*)(void *))stringHash;
101  m_hashFunc = hashFunc;
102  //m_compareFunc = (SINT32 (*)(void *,void *))stringCompare;
103  m_compareFunc = compareFunc;
104 }
105 
106 
107 Hashtable::~Hashtable()
108 {
109  m_pMutex->lock();
110 
111  for(SINT32 index = 0; index < m_capacity; index++)
112  {
113  struct Entry *e,*next;
114 
115  for(e = m_table[index]; e; e = next)
116  {
117  next = e->e_Next;
118  delete e;
119  e = NULL;
120  }
121  m_table[index] = NULL;
122  }
123  delete m_table;
124  m_table = NULL;
125  m_capacity = 0;
126  m_count = 0;
127  m_threshold = 0;
128  m_loadFactor = 0;
129  m_modCount = 0;
130  m_hashFunc = NULL;
131  m_compareFunc = NULL;
132 
133  m_pMutex->unlock();
134 
135  delete m_pMutex;
136  m_pMutex = NULL;
137 }
138 
139 
140 
141 
147 bool Hashtable::isEmpty()
148 {
149  return m_count == 0;
150 }
151 
152 
159 bool Hashtable::containsKey(void *key)
160 {
161  return getHashEntry(key) ? true : false;
162 }
163 
164 
171 void *Hashtable::getValue(void *key)
172 {
173  struct Entry *e = getHashEntry(key);
174 
175  return e ? e->e_Value : NULL;
176 }
177 
178 
192 void* Hashtable::put(void *key, void *value)
193 {
194  //CAMsg::printMsg(LOG_INFO, "Hashtable: Putting key.\n");
195 
196  if (!key || !value || !m_table)
197  {
198  return NULL;
199  }
200 
201  struct Entry *oldEntry = NULL;
202  struct Entry *newEntry = NULL;
203  UINT32 hash = m_hashFunc(key);
204  UINT32 index = hash % m_capacity;
205 
206  m_count++;
207  if (m_count >= m_threshold)
208  {
209  rehash();
210  }
211 
212  index = hash % m_capacity;
213 
214  newEntry = new Entry;
215  newEntry->e_Key = key;
216  newEntry->e_Value = value;
217  newEntry->e_Next = NULL;
218 
219  oldEntry = m_table[index];
220  if (!oldEntry)
221  {
222  m_table[index] = newEntry;
223  }
224  else
225  {
226  struct Entry *prevEntry = NULL;
227  for(; oldEntry; oldEntry = oldEntry->e_Next)
228  {
229  if (m_hashFunc(oldEntry->e_Key) == hash && !m_compareFunc(oldEntry->e_Key,key))
230  {
231  // found the same entry
232  newEntry->e_Next = oldEntry->e_Next;
233  break;
234  }
235  prevEntry = oldEntry;
236  }
237  if (prevEntry)
238  {
239  prevEntry->e_Next = newEntry;
240  }
241  else
242  {
243  m_table[index] = newEntry;
244  }
245  }
246 
247  return oldEntry;
248 }
249 
250 
261 void *Hashtable::remove(void *key)
262 {
263  //CAMsg::printMsg(LOG_INFO, "Hashtable: Removing key.\n");
264 
265  if (!key || !m_table)
266  {
267  return NULL;
268  }
269 
270  struct Entry *e,*prev;
271  UINT32 hash = m_hashFunc(key);
272 
273  for(e = m_table[hash % m_capacity], prev = NULL; e; e = e->e_Next)
274  {
275  if (m_hashFunc(e->e_Key) == hash && !m_compareFunc(e->e_Key,key))
276  {
277  void *value;
278 
279  //m_modCount++;
280  if (prev)
281  {
282  prev->e_Next = e->e_Next;
283  }
284  else
285  {
286  m_table[hash % m_capacity] = e->e_Next;
287  }
288 
289  m_count--;
290  value = e->e_Value;
291  e->e_Value = NULL;
292  e->e_Key = NULL;
293  e->e_Next = NULL;
294  delete e;
295  e = NULL;
296 
297  return value;
298  }
299  prev = e;
300  }
301 
302  return NULL;
303 }
304 
305 
306 void Hashtable::clear(SINT8 keyMode,SINT8 valueMode)
307 {
308  if (!m_table)
309  {
310  return;
311  }
312 
313  //CAMsg::printMsg(LOG_INFO, "Hashtable: Clearing...\n");
314 
315  for(SINT32 index = 0; index < m_capacity; index++)
316  {
317  struct Entry *e,*next;
318 
319  for(e = m_table[index]; e; e = next)
320  {
321  switch(keyMode)
322  {
323  case HASH_EMPTY_DELETE:
324  if (e->e_Key)
325  {
326  delete e->e_Key;
327  e->e_Key = NULL;
328  }
329  break;
330 // case HASH_EMPTY_FREE:
331 // free(e->e_Key);
332  default:
333  e->e_Key = NULL;
334  }
335  switch(valueMode)
336  {
337  case HASH_EMPTY_DELETE:
338  if (e->e_Value)
339  {
340  delete e->e_Value;
341  e->e_Value = NULL;
342  }
343  break;
344 // case HASH_EMPTY_FREE:
345 // free(e->e_Value);
346  default:
347  e->e_Value = NULL;
348  }
349  next = e->e_Next;
350  delete e;
351  e = NULL;
352  }
353  m_table[index] = NULL;
354  }
355  m_count = 0;
356 
357  //CAMsg::printMsg(LOG_INFO, "Hashtable: Has been cleared!\n");
358 }
359 
360 UINT32 Hashtable::getSize()
361 {
362  return m_count;
363 }
364 
365 UINT32 Hashtable::getCapacity()
366 {
367  return m_capacity;
368 }
369 
370 
376 bool Hashtable::rehash()
377 {
378  if (!m_table)
379  {
380  return false;
381  }
382 
383  CAMsg::printMsg(LOG_INFO, "Hashtable: Rehashing.\n");
384 
385  UINT32 (*hashCode)(void *) = m_hashFunc;
386  struct Entry **oldtable = m_table,**newtable;
387  SINT32 oldCapacity = m_capacity;
388  UINT32 newCapacity;
389 
390  newCapacity = oldCapacity * 2 + 1;
391  newtable = new Entry*[newCapacity];
392  for (UINT32 i = 0; i < newCapacity; i++)
393  {
394  newtable[i] = NULL;
395  }
396 
397  m_modCount++;
398  if (m_modCount > 10)
399  {
400  CAMsg::printMsg(LOG_INFO, "Hashtable: Too many rehash operations! Please adapt hashtable capacity to at least %d.\n", newCapacity);
401  }
402 
403  m_threshold = (UINT32)(newCapacity * m_loadFactor);
404  m_table = newtable;
405  m_capacity = newCapacity;
406 
407  for(SINT32 i = 0; i < oldCapacity; i++)
408  {
409  struct Entry *nextEntry, *e = NULL;
410  UINT32 index;
411 
412  for (nextEntry = oldtable[i]; nextEntry;)
413  {
414  e = nextEntry;
415  // save the previous next entry, as it will be deleted later
416  nextEntry = nextEntry->e_Next;
417 
418  index = hashCode(e->e_Key) % newCapacity;
419  /* If there has been another entry before, replace it.
420  * Delete the previous next entry in the same step.
421  */
422  e->e_Next = newtable[index];
423  newtable[index] = e;
424  }
425  }
426  delete oldtable;
427  oldtable = NULL;
428 
429  CAMsg::printMsg(LOG_INFO, "Hashtable: Rehashing complete.\n");
430 
431  return true;
432 }
433 
434 
442 struct Entry *Hashtable::getHashEntry(void *key)
443 {
444  if (!key || !m_table)
445  {
446  return NULL;
447  }
448 
449  struct Entry *e;
450  UINT32 hash = m_hashFunc(key);
451 
452  for(e = m_table[hash % m_capacity]; e; e = e->e_Next)
453  {
454  if (m_hashFunc(e->e_Key) == hash && !m_compareFunc(e->e_Key,key))
455  {
456  return e;
457  }
458  }
459 
460  return NULL;
461 }
462 
463 #endif //define PAYMENT
signed int SINT32
Definition: basetypedefs.h:132
signed char SINT8
Definition: basetypedefs.h:136
unsigned int UINT32
Definition: basetypedefs.h:131
static SINT32 printMsg(UINT32 typ, const char *format,...)
Writes a given message to the log.
Definition: CAMsg.cpp:251
Definition: Hashtable.cpp:43
void * e_Key
Definition: Hashtable.cpp:45
struct Entry * e_Next
Definition: Hashtable.cpp:44
void * e_Value
Definition: Hashtable.cpp:46