Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://bitbucket.org/Coin3D/
http://www.kongsberg.com/kogt/
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
SmHash.h
Go to the documentation of this file.
1 #ifndef SM_HASH_H
2 #define SM_HASH_H
3 
4 /**************************************************************************\
5  * Copyright (c) Kongsberg Oil & Gas Technologies AS
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * Neither the name of the copyright holder nor the names of its
20  * contributors may be used to endorse or promote products derived from
21  * this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 \**************************************************************************/
35 
36 // *************************************************************************
37 // This class (SmHash<Type, Key>) is internal and must not be exposed
38 // in the Coin API.
39 
40 // *************************************************************************
41 
42 #include <cassert>
43 #include <cstddef> // NULL
44 #include <cstring> // memset()
45 
46 #include <Inventor/lists/SbList.h>
48 #include <Inventor/C/tidbits.h>
49 
50 /* table containing the next prime number for all power of twos from
51  2^1 to 2^32 (the 2^32 prime is obviously less than 2^32 though) */
52 static unsigned long smhash_prime_table[32] = {
53  2,
54  5,
55  11,
56  17,
57  37,
58  67,
59  131,
60  257,
61  521,
62  1031,
63  2053,
64  4099,
65  8209,
66  16411,
67  32771,
68  65537,
69  131101,
70  262147,
71  524309,
72  1048583,
73  2097169,
74  4194319,
75  8388617,
76  16777259,
77  33554467,
78  67108879,
79  134217757,
80  268435459,
81  536870923,
82  1073741827,
83  2147483659U,
84  4294967291U /* 2^32 = 4294967296 */
85 };
86 
87 inline unsigned long
88 smhash_geq_prime_number(unsigned long num)
89 {
90  int i;
91  for (i = 0; i < 32; i++) {
92  if (smhash_prime_table[i] >= num) {
93  return smhash_prime_table[i];
94  }
95  }
96  /* just return num if we can't find a bigger prime number */
97  return num;
98 }
99 
100 // *************************************************************************
101 
102 // We usually implement inline functions below the class definition,
103 // since we think that makes the file more readable. However, this is
104  // not done for this class, since Microsoft Visual C++ is not too
105 // happy about having functions declared as inline for a template
106 // class.
107 
108 // *************************************************************************
109 
110 template <class Type, class Key>
111 class SmHashEntry {
112 public:
113 
114  void * operator new(size_t size, cc_memalloc * memhandler) {
117  entry->memhandler = memhandler;
118  return (void*) entry;
119  }
120  void operator delete(void * ptr) {
122  cc_memalloc_deallocate(entry->memhandler, ptr);
123  }
124  void operator delete(void * ptr, cc_memalloc * memhandler) {
126  cc_memalloc_deallocate(entry->memhandler, ptr);
127  }
128 
129  Key key;
130  Type obj;
133 };
134 
135 // *************************************************************************
136 
137 template <class Type, class Key>
138 class SmHash {
139 public:
140  typedef uintptr_t SmHashFunc(const Key & key);
141  typedef void SmHashApplyFunc(const Key & key, const Type & obj, void * closure);
142 
143 public:
144  SmHash(unsigned int sizearg = 256, float loadfactorarg = 0.0f)
145  {
146  this->commonConstructor(sizearg, loadfactorarg);
147  }
148 
149  SmHash(const SmHash & from)
150  {
151  this->commonConstructor(from.size, from.loadfactor);
152  this->operator=(from);
153  }
154 
155  SmHash & operator=(const SmHash & from)
156  {
157  this->clear();
158  from.apply(SmHash::copy_data, this);
159  return *this;
160  }
161 
163  {
164  this->clear();
165  cc_memalloc_destruct(this->memhandler);
166  delete [] this->buckets;
167  }
168 
169  void clear(void)
170  {
171  unsigned int i;
172  for ( i = 0; i < this->size; i++ ) {
173  while ( this->buckets[i] ) {
174  SmHashEntry<Type, Key> * entry = this->buckets[i];
175  this->buckets[i] = entry->next;
176  delete entry;
177  }
178  }
179  memset(this->buckets, 0, this->size * sizeof(SmHashEntry<Type, Key> *));
180  this->elements = 0;
181  }
182 
183  SbBool put(const Key & key, const Type & obj)
184  {
185  unsigned int i = this->getIndex(key);
186  SmHashEntry<Type, Key> * entry = this->buckets[i];
187  while ( entry ) {
188  if ( entry->key == key ) {
189  /* Replace the old value */
190  entry->obj = obj;
191  return FALSE;
192  }
193  entry = entry->next;
194  }
195 
196  /* Key not already in the hash table; insert a new
197  * entry as the first element in the bucket
198  */
199  entry = new (this->memhandler) SmHashEntry<Type, Key>;
200  entry->key = key;
201  entry->obj = obj;
202  entry->next = this->buckets[i];
203  this->buckets[i] = entry;
204 
205  if ( this->elements++ >= this->threshold ) {
206  this->resize((unsigned int) smhash_geq_prime_number(this->size + 1));
207  }
208  return TRUE;
209  }
210 
211  SbBool get(const Key & key, Type & obj) const
212  {
213  SmHashEntry<Type, Key> * entry;
214  unsigned int i = this->getIndex(key);
215  entry = this->buckets[i];
216  while ( entry ) {
217  if ( entry->key == key ) {
218  obj = entry->obj;
219  return TRUE;
220  }
221  entry = entry->next;
222  }
223  return FALSE;
224  }
225 
226  SbBool remove(const Key & key)
227  {
228  unsigned int i = this->getIndex(key);
229  SmHashEntry<Type, Key> * entry = this->buckets[i], * next, * prev = NULL;
230  while ( entry ) {
231  next = entry->next;
232  if ( entry->key == key ) {
233  this->elements--;
234  if ( prev == NULL) {
235  this->buckets[i] = next;
236  }
237  else {
238  prev->next = next;
239  }
240  delete entry;
241  return TRUE;
242  }
243  prev = entry;
244  entry = next;
245  }
246  return FALSE;
247  }
248 
249  void apply(SmHashApplyFunc * func, void * closure) const
250  {
251  unsigned int i;
252  SmHashEntry<Type, Key> * elem;
253  for ( i = 0; i < this->size; i++ ) {
254  elem = this->buckets[i];
255  while ( elem ) {
256  func(elem->key, elem->obj, closure);
257  elem = elem->next;
258  }
259  }
260  }
261 
262  void makeKeyList(SbList<Key> & l) const
263  {
264  this->apply(SmHash::add_to_list, &l);
265  }
266 
267  unsigned int getNumElements(void) const { return this->elements; }
268 
269  void setHashFunc(SmHashFunc * func) { this->hashfunc = func; }
270 
271 protected:
272  static uintptr_t default_hash_func(const Key & key) {
273  return (uintptr_t) key;
274  }
275 
276  unsigned int getIndex(const Key & key) const {
277  unsigned int idx = this->hashfunc(key);
278  return (idx % this->size);
279  }
280 
281  void resize(unsigned int newsize) {
282  /* we don't shrink the table */
283  if (this->size >= newsize) return;
284 
285  unsigned int oldsize = this->size;
286  SmHashEntry<Type, Key> ** oldbuckets = this->buckets;
287 
288  this->size = newsize;
289  this->elements = 0;
290  this->threshold = (unsigned int) (newsize * this->loadfactor);
291  this->buckets = new SmHashEntry<Type, Key> * [newsize];
292  memset(this->buckets, 0, this->size * sizeof(SmHashEntry<Type, Key> *));
293 
294  /* Transfer all mappings */
295  unsigned int i;
296  for ( i = 0; i < oldsize; i++ ) {
297  SmHashEntry<Type, Key> * entry = oldbuckets[i];
298  while ( entry ) {
299  this->put(entry->key, entry->obj);
300  SmHashEntry<Type, Key> * preventry = entry;
301  entry = entry->next;
302  delete preventry;
303  }
304  }
305  delete [] oldbuckets;
306  }
307 
308 private:
309  void commonConstructor(unsigned int sizearg, float loadfactorarg)
310  {
311  if ( loadfactorarg <= 0.0f ) { loadfactorarg = 0.75f; }
312  unsigned int s = smhash_geq_prime_number(sizearg);
313  this->memhandler = cc_memalloc_construct(sizeof(SmHashEntry<Type, Key>));
314  this->size = s;
315  this->elements = 0;
316  this->threshold = (unsigned int) (s * loadfactorarg);
317  this->loadfactor = loadfactorarg;
318  this->buckets = new SmHashEntry<Type, Key> * [this->size];
319  memset(this->buckets, 0, this->size * sizeof(SmHashEntry<Type, Key> *));
320  this->hashfunc = default_hash_func;
321  }
322 
323  void getStats(int & buckets_used, int & buckets, int & elements, float & chain_length_avg, int & chain_length_max)
324  {
325  unsigned int i;
326  buckets_used = 0, chain_length_max = 0;
327  for ( i = 0; i < this->size; i++ ) {
328  if ( this->buckets[i] ) {
329  unsigned int chain_l = 0;
330  SmHashEntry<Type, Key> * entry = this->buckets[i];
331  buckets_used++;
332  while ( entry ) {
333  chain_l++;
334  entry = entry->next;
335  }
336  if ( chain_l > chain_length_max ) { chain_length_max = chain_l; }
337  }
338  }
339  buckets = this->size;
340  elements = this->elements;
341  chain_length_avg = (float) this->elements / buckets_used;
342  }
343 
344  static void copy_data(const Key & key, const Type & obj, void * closure)
345  {
346  SmHash * thisp = (SmHash *)closure;
347  thisp->put(key, obj);
348  }
349 
350  static void add_to_list(const Key & key, const Type & obj, void * closure)
351  {
352  SbList<Key> * l = (SbList<Key> *)closure;
353  l->append(key);
354  }
355 
356  float loadfactor;
357  unsigned int size;
358  unsigned int elements;
359  unsigned int threshold;
360 
361  SmHashEntry<Type, Key> ** buckets;
362  SmHashFunc * hashfunc;
363  cc_memalloc * memhandler;
364 };
365 
366 #endif // !SM_HASH_H
struct cc_memalloc cc_memalloc
Type obj
Definition: SmHash.h:130
Definition: SmHash.h:138
Key key
Definition: SmHash.h:129
void append(const Type item)
Definition: SbList.h:187
Definition: SbList.h:69
~SmHash()
Definition: SmHash.h:162
cc_memalloc * cc_memalloc_construct(const unsigned int unitsize)
SmHash(const SmHash &from)
Definition: SmHash.h:149
unsigned int getNumElements(void) const
Definition: SmHash.h:267
static unsigned long smhash_prime_table[32]
Definition: SmHash.h:52
Definition: SmHash.h:111
void cc_memalloc_destruct(cc_memalloc *allocator)
void resize(unsigned int newsize)
Definition: SmHash.h:281
void SmHashApplyFunc(const Key &key, const Type &obj, void *closure)
Definition: SmHash.h:141
SmHash & operator=(const SmHash &from)
Definition: SmHash.h:155
void * cc_memalloc_allocate(cc_memalloc *allocator)
SmHash(unsigned int sizearg=256, float loadfactorarg=0.0f)
Definition: SmHash.h:144
void makeKeyList(SbList< Key > &l) const
Definition: SmHash.h:262
SbBool put(const Key &key, const Type &obj)
Definition: SmHash.h:183
static uintptr_t default_hash_func(const Key &key)
Definition: SmHash.h:272
SmHashEntry< Type, Key > * next
Definition: SmHash.h:131
cc_memalloc * memhandler
Definition: SmHash.h:132
void setHashFunc(SmHashFunc *func)
Definition: SmHash.h:269
unsigned long smhash_geq_prime_number(unsigned long num)
Definition: SmHash.h:88
void cc_memalloc_deallocate(cc_memalloc *allocator, void *ptr)
void clear(void)
Definition: SmHash.h:169
void apply(SmHashApplyFunc *func, void *closure) const
Definition: SmHash.h:249
uintptr_t SmHashFunc(const Key &key)
Definition: SmHash.h:140
unsigned int getIndex(const Key &key) const
Definition: SmHash.h:276