VirtualBox

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

Last change on this file since 31808 was 31808, checked in by vboxsync, 14 years ago

crOpenGL: resource sharing between contexts

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.6 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 void 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;
270 }
271 f = f->next;
272 }
273
274 /* if we get here, the ID was already allocated - that's OK */
275}
276
277
278/*
279 * Determine if the given id is free. Return GL_TRUE if so.
280 */
281static GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
282{
283 FreeElem *i;
284
285 /* First find which region it fits in */
286 for (i = pool->freeList; i && !(i->min <= id && id <= i->max); i=i->next)
287 {
288 /* EMPTY BODY */
289 }
290
291 if (i)
292 return GL_TRUE;
293 else
294 return GL_FALSE;
295}
296
297
298
299CRHashTable *crAllocHashtable( void )
300{
301 int i;
302 CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
303 hash->num_elements = 0;
304 for (i = 0 ; i < CR_NUM_BUCKETS ; i++)
305 {
306 hash->buckets[i] = NULL;
307 }
308 hash->idPool = crAllocHashIdPool();
309#ifdef CHROMIUM_THREADSAFE
310 crInitMutex(&hash->mutex);
311#endif
312 return hash;
313}
314
315void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
316{
317 int i;
318 CRHashNode *entry, *next;
319
320 if ( !hash) return;
321
322#ifdef CHROMIUM_THREADSAFE
323 crLockMutex(&hash->mutex);
324#endif
325
326 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
327 {
328 entry = hash->buckets[i];
329 while (entry)
330 {
331 next = entry->next;
332 /* Clear the key in case crHashtableDelete() is called
333 * from this callback.
334 */
335 entry->key = 0;
336 if (deleteFunc && entry->data)
337 {
338 (*deleteFunc)(entry->data);
339 }
340 crFree(entry);
341 entry = next;
342
343 }
344 }
345 crFreeHashIdPool( hash->idPool );
346
347#ifdef CHROMIUM_THREADSAFE
348 crUnlockMutex(&hash->mutex);
349 crFreeMutex(&hash->mutex);
350#endif
351
352 crFree( hash );
353}
354
355
356void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
357{
358 int i;
359 CRHashNode *entry, *next;
360
361 if (!hash)
362 return;
363
364#ifdef CHROMIUM_THREADSAFE
365 crLockMutex(&hash->mutex);
366#endif
367 for (i = 0; i < CR_NUM_BUCKETS; i++)
368 {
369 entry = hash->buckets[i];
370 while (entry)
371 {
372 /* save next ptr here, in case walkFunc deletes this entry */
373 next = entry->next;
374 if (entry->data && walkFunc) {
375 (*walkFunc)( entry->key, entry->data, dataPtr2 );
376 }
377 entry = next;
378 }
379 }
380#ifdef CHROMIUM_THREADSAFE
381 crUnlockMutex(&hash->mutex);
382#endif
383}
384
385static unsigned int crHash( unsigned long key )
386{
387 return key % CR_NUM_BUCKETS;
388}
389
390void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
391{
392 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
393#ifdef CHROMIUM_THREADSAFE
394 crLockMutex(&h->mutex);
395#endif
396 node->key = key;
397 node->data = data;
398 node->next = h->buckets[crHash( key )];
399 h->buckets[ crHash( key ) ] = node;
400 h->num_elements++;
401 crHashIdPoolAllocId (h->idPool, key);
402#ifdef CHROMIUM_THREADSAFE
403 crUnlockMutex(&h->mutex);
404#endif
405}
406
407GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
408{
409 GLuint res;
410 int i;
411
412#ifdef CHROMIUM_THREADSAFE
413 crLockMutex(&h->mutex);
414#endif
415 res = crHashIdPoolAllocBlock (h->idPool, range);
416#ifdef CHROMIUM_THREADSAFE
417 crUnlockMutex(&h->mutex);
418#endif
419 return res;
420}
421
422void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
423{
424 unsigned int index = crHash( key );
425 CRHashNode *temp, *beftemp = NULL;
426
427#ifdef CHROMIUM_THREADSAFE
428 crLockMutex(&h->mutex);
429#endif
430 for ( temp = h->buckets[index]; temp; temp = temp->next )
431 {
432 if ( temp->key == key )
433 break;
434 beftemp = temp;
435 }
436 if ( !temp ) {
437#ifdef CHROMIUM_THREADSAFE
438 crUnlockMutex(&h->mutex);
439#endif
440 return; /* not an error */
441 }
442 if ( beftemp )
443 beftemp->next = temp->next;
444 else
445 h->buckets[index] = temp->next;
446 h->num_elements--;
447 if (temp->data && deleteFunc) {
448 (*deleteFunc)( temp->data );
449 }
450
451 crFree( temp );
452
453 crHashIdPoolFreeBlock( h->idPool, key, 1 );
454#ifdef CHROMIUM_THREADSAFE
455 crUnlockMutex(&h->mutex);
456#endif
457}
458
459void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
460{
461 /* XXX optimize someday */
462 GLuint i;
463 for (i = 0; i < (GLuint)range; i++) {
464 crHashtableDelete( h, key, deleteFunc );
465 }
466}
467
468void *crHashtableSearch( const CRHashTable *h, unsigned long key )
469{
470 unsigned int index = crHash( key );
471 CRHashNode *temp;
472#ifdef CHROMIUM_THREADSAFE
473 crLockMutex((CRmutex *)&h->mutex);
474#endif
475 for ( temp = h->buckets[index]; temp; temp = temp->next )
476 {
477 if ( temp->key == key )
478 break;
479 }
480#ifdef CHROMIUM_THREADSAFE
481 crUnlockMutex((CRmutex *)&h->mutex);
482#endif
483 if ( !temp )
484 {
485 return NULL;
486 }
487 return temp->data;
488}
489
490void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
491 CRHashtableCallback deleteFunc)
492{
493 unsigned int index = crHash( key );
494 CRHashNode *temp;
495#ifdef CHROMIUM_THREADSAFE
496 crLockMutex(&h->mutex);
497#endif
498 for ( temp = h->buckets[index]; temp; temp = temp->next )
499 {
500 if ( temp->key == key )
501 break;
502 }
503#ifdef CHROMIUM_THREADSAFE
504 crUnlockMutex(&h->mutex);
505#endif
506 if ( !temp )
507 {
508 crHashtableAdd( h, key, data );
509 return;
510 }
511#ifdef CHROMIUM_THREADSAFE
512 crLockMutex(&h->mutex);
513#endif
514 if ( temp->data && deleteFunc )
515 {
516 (*deleteFunc)( temp->data );
517 }
518 temp->data = data;
519#ifdef CHROMIUM_THREADSAFE
520 crUnlockMutex(&h->mutex);
521#endif
522}
523
524unsigned int crHashtableNumElements( const CRHashTable *h)
525{
526 if (h)
527 return h->num_elements;
528 else
529 return 0;
530}
531
532/*
533 * Determine if the given key is used. Return GL_TRUE if so.
534 */
535GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
536{
537 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
538}
539
540GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
541{
542 int i;
543 CRHashNode *entry;
544 GLboolean rc = GL_FALSE;
545
546 if (!pHash)
547 return rc;
548
549#ifdef CHROMIUM_THREADSAFE
550 crLockMutex(&pHash->mutex);
551#endif
552 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
553 {
554 entry = pHash->buckets[i];
555 while (entry)
556 {
557 if (entry->data == pData) {
558 if (pKey)
559 *pKey = entry->key;
560 rc = GL_TRUE;
561 break;
562 }
563 entry = entry->next;
564 }
565 }
566#ifdef CHROMIUM_THREADSAFE
567 crUnlockMutex(&pHash->mutex);
568#endif
569
570 return rc;
571}
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