SmallChange  1.0.0
A collection of extensions to Coin3D
Loading...
Searching...
No Matches
SmHash.h
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>
47#include <Inventor/C/base/memalloc.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) */
52static 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
87inline unsigned long
88smhash_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
110template <class Type, class Key>
112public:
113
114 void * operator new(size_t size, cc_memalloc * memhandler) {
116 cc_memalloc_allocate(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;
132 cc_memalloc * memhandler;
133};
134
135// *************************************************************************
136
137template <class Type, class Key>
138class SmHash {
139public:
140 typedef uintptr_t SmHashFunc(const Key & key);
141 typedef void SmHashApplyFunc(const Key & key, const Type & obj, void * closure);
142
143public:
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
162 ~SmHash()
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 {
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;
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
271protected:
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
308private:
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
Definition misc/SbList.h:69
Definition SmHash.h:111
Definition SmHash.h:138