VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/hash.c@ 44326

Last change on this file since 44326 was 44291, checked in by vboxsync, 12 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.1 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_threads.h"
8#include "cr_hash.h"
9#include "cr_mem.h"
10#include "cr_error.h"
11
12#include <iprt/list.h>
13
14#define CR_MAXUINT ((GLuint) 0xFFFFFFFF)
15#define CR_HASH_ID_MIN ((GLuint)1)
16#define CR_HASH_ID_MAX CR_MAXUINT
17
18#define CR_NUM_BUCKETS 1047
19
20typedef struct FreeElemRec {
21 RTLISTNODE Node;
22 GLuint min;
23 GLuint max;
24} FreeElem;
25
26struct CRHashIdPool {
27 RTLISTNODE freeList;
28};
29
30typedef struct CRHashNode {
31 unsigned long key;
32 void *data;
33 struct CRHashNode *next;
34} CRHashNode;
35
36struct CRHashTable {
37 unsigned int num_elements;
38 CRHashNode *buckets[CR_NUM_BUCKETS];
39 CRHashIdPool *idPool;
40#ifdef CHROMIUM_THREADSAFE
41 CRmutex mutex;
42#endif
43};
44
45
46CRHashIdPool *crAllocHashIdPool( void )
47{
48 CRHashIdPool *pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
49 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
50 RTListInit(&pool->freeList);
51 elem->min = CR_HASH_ID_MIN;
52 elem->max = CR_HASH_ID_MAX;
53 RTListAppend(&pool->freeList, &elem->Node);
54 return pool;
55}
56
57void crFreeHashIdPool( CRHashIdPool *pool )
58{
59 FreeElem *i, *next;
60 RTListForEachSafe(&pool->freeList, i, next, FreeElem, Node)
61 {
62 crFree(i);
63 }
64
65 crFree(pool);
66}
67
68#ifdef DEBUG_misha
69static void crHashIdPoolDbgCheckConsistency(CRHashIdPool *pool)
70{
71 FreeElem *i;
72 GLuint min = 0;
73
74 /* null is a special case, it is always treated as allocated */
75 Assert(!crHashIdPoolIsIdFree(pool, 0));
76
77 /* first ensure entries have correct values */
78 RTListForEach(&pool->freeList, i, FreeElem, Node)
79 {
80 Assert(i->min >= CR_HASH_ID_MIN);
81 Assert(i->max <= CR_HASH_ID_MAX);
82 Assert(i->min < i->max);
83 }
84
85 /* now ensure entries do not intersect */
86 /* and that they are sorted */
87 RTListForEach(&pool->freeList, i, FreeElem, Node)
88 {
89 Assert(min < i->min);
90 min = i->max;
91 }
92}
93
94static void crHashIdPoolDbgCheckUsed( const CRHashIdPool *pool, GLuint start, GLuint count, GLboolean fUsed )
95{
96 GLuint i;
97 CRASSERT(count);
98 CRASSERT(start >= CR_HASH_ID_MIN);
99 CRASSERT(start + count <= CR_HASH_ID_MAX);
100 CRASSERT(start + count > start);
101 for (i = 0; i < count; ++i)
102 {
103 Assert(!fUsed == !!crHashIdPoolIsIdFree( pool, start + i ));
104 }
105}
106
107# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { \
108 crHashIdPoolDbgCheckConsistency((_p)); \
109 crHashIdPoolDbgCheckUsed( (_p), (_start), (_count), (_used) ); \
110 } while (0)
111
112# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { crHashIdPoolDbgCheckConsistency((_p)); } while (0)
113#else
114# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { } while (0)
115# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { } while (0)
116#endif
117
118/*
119 * Allocate a block of <count> IDs. Return index of first one.
120 * Return 0 if we fail.
121 */
122GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
123{
124 FreeElem *f, *next;
125 GLuint ret;
126
127 CRASSERT(count > 0);
128 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
129 {
130 Assert(f->max > f->min);
131 if (f->max - f->min >= (GLuint) count)
132 {
133 /* found a sufficiently large enough block */
134 ret = f->min;
135 f->min += count;
136 if (f->min == f->max)
137 {
138 RTListNodeRemove(&f->Node);
139 crFree(f);
140 }
141
142 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, ret, count, GL_TRUE);
143 return ret;
144 }
145 }
146
147 /* failed to find free block */
148 crWarning("crHashIdPoolAllocBlock failed");
149 CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(pool);
150 return 0;
151}
152
153
154/*
155 * Free a block of <count> IDs starting at <first>.
156 */
157void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
158{
159 FreeElem *f;
160 GLuint last;
161 GLuint newMax;
162 FreeElem *cur, *curNext;
163
164 /* null is a special case, it is always treated as allocated */
165 if (!first)
166 {
167 Assert(!crHashIdPoolIsIdFree(pool, 0));
168 ++first;
169 --count;
170 if (!count)
171 return;
172 }
173
174 last = first + count;
175 CRASSERT(count > 0);
176 CRASSERT(last > first);
177 CRASSERT(first >= CR_HASH_ID_MIN);
178 CRASSERT(last <= CR_HASH_ID_MAX);
179
180 /* the id list is sorted, first find a place to insert */
181 RTListForEach(&pool->freeList, f, FreeElem, Node)
182 {
183 Assert(f->max > f->min);
184
185 if (f->max < first)
186 continue;
187
188 if (f->min > last)
189 {
190 /* we are here because first is > than prevEntry->max
191 * otherwise the previous loop iterations should handle that */
192 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
193 elem->min = first;
194 elem->max = last;
195 RTListNodeInsertBefore(&f->Node, &elem->Node);
196 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
197 return;
198 }
199
200 /* now we have f->min <= last and f->max >= first,
201 * so we have either intersection */
202
203 if (f->min > first)
204 f->min = first; /* first is guarantied not to touch any prev regions */
205
206 newMax = last;
207
208 if (f->max >= last)
209 {
210 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
211 return;
212 }
213
214 for (cur = RTListNodeGetNext(&f->Node, FreeElem, Node),
215 curNext = RT_FROM_MEMBER(cur->Node.pNext, FreeElem, Node);
216 !RTListNodeIsDummy(&pool->freeList, cur, FreeElem, Node);
217 cur = curNext,
218 curNext = RT_FROM_MEMBER((cur)->Node.pNext, FreeElem, Node) )
219 {
220 if (cur->min > last)
221 break;
222
223 newMax = cur->max;
224 RTListNodeRemove(&cur->Node);
225 crFree(cur);
226
227 if (newMax >= last)
228 break;
229 }
230
231 f->max = newMax;
232 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
233 return;
234 }
235
236 /* we are here because either the list is empty or because all list rande elements have smaller values */
237 f = (FreeElem *) crCalloc(sizeof(FreeElem));
238 f->min = first;
239 f->max = last;
240 RTListAppend(&pool->freeList, &f->Node);
241 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
242}
243
244
245
246/*
247 * Mark the given Id as being allocated.
248 */
249GLboolean crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
250{
251 FreeElem *f, *next;
252
253 if (!id)
254 {
255 /* null is a special case, it is always treated as allocated */
256 Assert(!crHashIdPoolIsIdFree(pool, 0));
257 return GL_FALSE;
258 }
259
260// Assert(id != 2);
261
262 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
263 {
264 if (f->max <= id)
265 continue;
266 if (f->min > id)
267 {
268 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
269 return GL_FALSE;
270 }
271
272 /* f->min <= id && f->max > id */
273 if (id > f->min)
274 {
275 if (id + 1 < f->max)
276 {
277 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
278 elem->min = id + 1;
279 elem->max = f->max;
280 RTListNodeInsertAfter(&f->Node, &elem->Node);
281 }
282 f->max = id;
283
284 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
285 }
286 else
287 {
288 Assert(id == f->min);
289 if (id + 1 < f->max)
290 {
291 f->min = id + 1;
292 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
293 }
294 else
295 {
296 RTListNodeRemove(&f->Node);
297 crFree(f);
298 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
299 }
300 }
301
302 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
303 return GL_TRUE;
304 }
305
306 /* if we get here, the ID was already allocated - that's OK */
307 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
308 return GL_FALSE;
309}
310
311
312/*
313 * Determine if the given id is free. Return GL_TRUE if so.
314 */
315GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
316{
317 FreeElem *f;
318 CRASSERT(id >= 0);
319 CRASSERT(id <= CR_HASH_ID_MAX);
320
321 RTListForEach(&pool->freeList, f, FreeElem, Node)
322 {
323 if (f->max <= id)
324 continue;
325 if (f->min > id)
326 return GL_FALSE;
327 return GL_TRUE;
328 }
329 return GL_FALSE;
330}
331
332
333
334CRHashTable *crAllocHashtable( void )
335{
336 int i;
337 CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
338 hash->num_elements = 0;
339 for (i = 0 ; i < CR_NUM_BUCKETS ; i++)
340 {
341 hash->buckets[i] = NULL;
342 }
343 hash->idPool = crAllocHashIdPool();
344#ifdef CHROMIUM_THREADSAFE
345 crInitMutex(&hash->mutex);
346#endif
347 return hash;
348}
349
350void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
351{
352 int i;
353 CRHashNode *entry, *next;
354
355 if ( !hash) return;
356
357#ifdef CHROMIUM_THREADSAFE
358 crLockMutex(&hash->mutex);
359#endif
360
361 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
362 {
363 entry = hash->buckets[i];
364 while (entry)
365 {
366 next = entry->next;
367 /* Clear the key in case crHashtableDelete() is called
368 * from this callback.
369 */
370 entry->key = 0;
371 if (deleteFunc && entry->data)
372 {
373 (*deleteFunc)(entry->data);
374 }
375 crFree(entry);
376 entry = next;
377
378 }
379 }
380 crFreeHashIdPool( hash->idPool );
381
382#ifdef CHROMIUM_THREADSAFE
383 crUnlockMutex(&hash->mutex);
384 crFreeMutex(&hash->mutex);
385#endif
386
387 crFree( hash );
388}
389
390void crHashtableLock(CRHashTable *h)
391{
392#ifdef CHROMIUM_THREADSAFE
393 crLockMutex(&h->mutex);
394#endif
395}
396
397void crHashtableUnlock(CRHashTable *h)
398{
399#ifdef CHROMIUM_THREADSAFE
400 crUnlockMutex(&h->mutex);
401#endif
402}
403
404void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
405{
406 int i;
407 CRHashNode *entry, *next;
408
409 if (!hash)
410 return;
411
412#ifdef CHROMIUM_THREADSAFE
413 crLockMutex(&hash->mutex);
414#endif
415 for (i = 0; i < CR_NUM_BUCKETS; i++)
416 {
417 entry = hash->buckets[i];
418 while (entry)
419 {
420 /* save next ptr here, in case walkFunc deletes this entry */
421 next = entry->next;
422 if (entry->data && walkFunc) {
423 (*walkFunc)( entry->key, entry->data, dataPtr2 );
424 }
425 entry = next;
426 }
427 }
428#ifdef CHROMIUM_THREADSAFE
429 crUnlockMutex(&hash->mutex);
430#endif
431}
432
433static unsigned int crHash( unsigned long key )
434{
435 return key % CR_NUM_BUCKETS;
436}
437
438void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
439{
440 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
441#ifdef CHROMIUM_THREADSAFE
442 crLockMutex(&h->mutex);
443#endif
444 node->key = key;
445 node->data = data;
446 node->next = h->buckets[crHash( key )];
447 h->buckets[ crHash( key ) ] = node;
448 h->num_elements++;
449 crHashIdPoolAllocId (h->idPool, key);
450#ifdef CHROMIUM_THREADSAFE
451 crUnlockMutex(&h->mutex);
452#endif
453}
454
455GLboolean crHashtableAllocRegisterKey( CRHashTable *h, GLuint key)
456{
457 GLboolean fAllocated;
458#ifdef CHROMIUM_THREADSAFE
459 crLockMutex(&h->mutex);
460#endif
461 fAllocated = crHashIdPoolAllocId (h->idPool, key);
462#ifdef CHROMIUM_THREADSAFE
463 crUnlockMutex(&h->mutex);
464#endif
465 return fAllocated;
466}
467
468GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
469{
470 GLuint res;
471 int i;
472
473#ifdef CHROMIUM_THREADSAFE
474 crLockMutex(&h->mutex);
475#endif
476 res = crHashIdPoolAllocBlock (h->idPool, range);
477#ifdef DEBUG_misha
478 Assert(res);
479 for (i = 0; i < range; ++i)
480 {
481 void *search = crHashtableSearch( h, res+i );
482 Assert(!search);
483 }
484#endif
485#ifdef CHROMIUM_THREADSAFE
486 crUnlockMutex(&h->mutex);
487#endif
488 return res;
489}
490
491void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
492{
493 unsigned int index = crHash( key );
494 CRHashNode *temp, *beftemp = NULL;
495
496#ifdef CHROMIUM_THREADSAFE
497 crLockMutex(&h->mutex);
498#endif
499 for ( temp = h->buckets[index]; temp; temp = temp->next )
500 {
501 if ( temp->key == key )
502 break;
503 beftemp = temp;
504 }
505 if ( !temp ) {
506#ifdef CHROMIUM_THREADSAFE
507 crUnlockMutex(&h->mutex);
508#endif
509 return; /* not an error */
510 }
511 if ( beftemp )
512 beftemp->next = temp->next;
513 else
514 h->buckets[index] = temp->next;
515 h->num_elements--;
516 if (temp->data && deleteFunc) {
517 (*deleteFunc)( temp->data );
518 }
519
520 crFree( temp );
521
522 crHashIdPoolFreeBlock( h->idPool, key, 1 );
523#ifdef CHROMIUM_THREADSAFE
524 crUnlockMutex(&h->mutex);
525#endif
526}
527
528void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
529{
530 /* XXX optimize someday */
531 GLuint i;
532 for (i = 0; i < (GLuint)range; i++) {
533 crHashtableDelete( h, key, deleteFunc );
534 }
535}
536
537void *crHashtableSearch( const CRHashTable *h, unsigned long key )
538{
539 unsigned int index = crHash( key );
540 CRHashNode *temp;
541#ifdef CHROMIUM_THREADSAFE
542 crLockMutex((CRmutex *)&h->mutex);
543#endif
544 for ( temp = h->buckets[index]; temp; temp = temp->next )
545 {
546 if ( temp->key == key )
547 break;
548 }
549#ifdef CHROMIUM_THREADSAFE
550 crUnlockMutex((CRmutex *)&h->mutex);
551#endif
552 if ( !temp )
553 {
554 return NULL;
555 }
556 return temp->data;
557}
558
559void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
560 CRHashtableCallback deleteFunc)
561{
562 unsigned int index = crHash( key );
563 CRHashNode *temp;
564#ifdef CHROMIUM_THREADSAFE
565 crLockMutex(&h->mutex);
566#endif
567 for ( temp = h->buckets[index]; temp; temp = temp->next )
568 {
569 if ( temp->key == key )
570 break;
571 }
572#ifdef CHROMIUM_THREADSAFE
573 crUnlockMutex(&h->mutex);
574#endif
575 if ( !temp )
576 {
577 crHashtableAdd( h, key, data );
578 return;
579 }
580#ifdef CHROMIUM_THREADSAFE
581 crLockMutex(&h->mutex);
582#endif
583 if ( temp->data && deleteFunc )
584 {
585 (*deleteFunc)( temp->data );
586 }
587 temp->data = data;
588#ifdef CHROMIUM_THREADSAFE
589 crUnlockMutex(&h->mutex);
590#endif
591}
592
593unsigned int crHashtableNumElements( const CRHashTable *h)
594{
595 if (h)
596 return h->num_elements;
597 else
598 return 0;
599}
600
601/*
602 * Determine if the given key is used. Return GL_TRUE if so.
603 */
604GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
605{
606 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
607}
608
609GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
610{
611 int i;
612 CRHashNode *entry;
613 GLboolean rc = GL_FALSE;
614
615 if (!pHash)
616 return rc;
617
618#ifdef CHROMIUM_THREADSAFE
619 crLockMutex(&pHash->mutex);
620#endif
621 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
622 {
623 entry = pHash->buckets[i];
624 while (entry)
625 {
626 if (entry->data == pData) {
627 if (pKey)
628 *pKey = entry->key;
629 rc = GL_TRUE;
630 break;
631 }
632 entry = entry->next;
633 }
634 }
635#ifdef CHROMIUM_THREADSAFE
636 crUnlockMutex(&pHash->mutex);
637#endif
638
639 return rc;
640}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette