VirtualBox

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

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

crOpenGL: fix guest state bits

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

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