VirtualBox

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

Last change on this file since 15707 was 15532, checked in by vboxsync, 16 years ago

crOpenGL: export to OSE

  • 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
319 if ( !hash) return;
320
321#ifdef CHROMIUM_THREADSAFE
322 crLockMutex(&hash->mutex);
323#endif
324
325 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
326 {
327 if ( hash->buckets[i] )
328 {
329 if (hash->buckets[i]->data && deleteFunc) {
330 /* Clear the key in case crHashtableDelete() is called
331 * from this callback.
332 */
333 hash->buckets[i]->key = 0;
334 (*deleteFunc)( hash->buckets[i]->data );
335 }
336 crFree( hash->buckets[i] );
337 }
338 }
339 crFreeHashIdPool( hash->idPool );
340
341#ifdef CHROMIUM_THREADSAFE
342 crUnlockMutex(&hash->mutex);
343 crFreeMutex(&hash->mutex);
344#endif
345
346 crFree( hash );
347}
348
349
350void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
351{
352 int i;
353 CRHashNode *entry, *next;
354
355 if (!hash)
356 return;
357
358#ifdef CHROMIUM_THREADSAFE
359 crLockMutex(&hash->mutex);
360#endif
361 for (i = 0; i < CR_NUM_BUCKETS; i++)
362 {
363 entry = hash->buckets[i];
364 while (entry)
365 {
366 /* save next ptr here, in case walkFunc deletes this entry */
367 next = entry->next;
368 if (entry->data && walkFunc) {
369 (*walkFunc)( entry->key, entry->data, dataPtr2 );
370 }
371 entry = next;
372 }
373 }
374#ifdef CHROMIUM_THREADSAFE
375 crUnlockMutex(&hash->mutex);
376#endif
377}
378
379static unsigned int crHash( unsigned long key )
380{
381 return key % CR_NUM_BUCKETS;
382}
383
384void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
385{
386 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
387#ifdef CHROMIUM_THREADSAFE
388 crLockMutex(&h->mutex);
389#endif
390 node->key = key;
391 node->data = data;
392 node->next = h->buckets[crHash( key )];
393 h->buckets[ crHash( key ) ] = node;
394 h->num_elements++;
395 crHashIdPoolAllocId (h->idPool, key);
396#ifdef CHROMIUM_THREADSAFE
397 crUnlockMutex(&h->mutex);
398#endif
399}
400
401GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
402{
403 GLuint res;
404 int i;
405
406#ifdef CHROMIUM_THREADSAFE
407 crLockMutex(&h->mutex);
408#endif
409 res = crHashIdPoolAllocBlock (h->idPool, range);
410#ifdef CHROMIUM_THREADSAFE
411 crUnlockMutex(&h->mutex);
412#endif
413 for ( i = 0; i < range; i++)
414 crHashtableAdd( h, i + res , NULL );
415 return res;
416}
417
418void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
419{
420 unsigned int index = crHash( key );
421 CRHashNode *temp, *beftemp = NULL;
422
423#ifdef CHROMIUM_THREADSAFE
424 crLockMutex(&h->mutex);
425#endif
426 for ( temp = h->buckets[index]; temp; temp = temp->next )
427 {
428 if ( temp->key == key )
429 break;
430 beftemp = temp;
431 }
432 if ( !temp ) {
433#ifdef CHROMIUM_THREADSAFE
434 crUnlockMutex(&h->mutex);
435#endif
436 return; /* not an error */
437 }
438 if ( beftemp )
439 beftemp->next = temp->next;
440 else
441 h->buckets[index] = temp->next;
442 h->num_elements--;
443 if (temp->data && deleteFunc) {
444 (*deleteFunc)( temp->data );
445 }
446
447 crFree( temp );
448
449 crHashIdPoolFreeBlock( h->idPool, key, 1 );
450#ifdef CHROMIUM_THREADSAFE
451 crUnlockMutex(&h->mutex);
452#endif
453}
454
455void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
456{
457 /* XXX optimize someday */
458 GLuint i;
459 for (i = 0; i < (GLuint)range; i++) {
460 crHashtableDelete( h, key, deleteFunc );
461 }
462}
463
464void *crHashtableSearch( const CRHashTable *h, unsigned long key )
465{
466 unsigned int index = crHash( key );
467 CRHashNode *temp;
468#ifdef CHROMIUM_THREADSAFE
469 crLockMutex((CRmutex *)&h->mutex);
470#endif
471 for ( temp = h->buckets[index]; temp; temp = temp->next )
472 {
473 if ( temp->key == key )
474 break;
475 }
476#ifdef CHROMIUM_THREADSAFE
477 crUnlockMutex((CRmutex *)&h->mutex);
478#endif
479 if ( !temp )
480 {
481 return NULL;
482 }
483 return temp->data;
484}
485
486void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
487 CRHashtableCallback deleteFunc)
488{
489 unsigned int index = crHash( key );
490 CRHashNode *temp;
491#ifdef CHROMIUM_THREADSAFE
492 crLockMutex(&h->mutex);
493#endif
494 for ( temp = h->buckets[index]; temp; temp = temp->next )
495 {
496 if ( temp->key == key )
497 break;
498 }
499#ifdef CHROMIUM_THREADSAFE
500 crUnlockMutex(&h->mutex);
501#endif
502 if ( !temp )
503 {
504 crHashtableAdd( h, key, data );
505 return;
506 }
507#ifdef CHROMIUM_THREADSAFE
508 crLockMutex(&h->mutex);
509#endif
510 if ( temp->data && deleteFunc )
511 {
512 (*deleteFunc)( temp->data );
513 }
514 temp->data = data;
515#ifdef CHROMIUM_THREADSAFE
516 crUnlockMutex(&h->mutex);
517#endif
518}
519
520unsigned int crHashtableNumElements( const CRHashTable *h)
521{
522 if (h)
523 return h->num_elements;
524 else
525 return 0;
526}
527
528/*
529 * Determine if the given key is used. Return GL_TRUE if so.
530 */
531GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
532{
533 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
534}
535
536GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
537{
538 int i;
539 CRHashNode *entry;
540 GLboolean rc = GL_FALSE;
541
542 if (!pHash)
543 return rc;
544
545#ifdef CHROMIUM_THREADSAFE
546 crLockMutex(&pHash->mutex);
547#endif
548 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
549 {
550 entry = pHash->buckets[i];
551 while (entry)
552 {
553 if (entry->data == pData) {
554 if (pKey)
555 *pKey = entry->key;
556 rc = GL_TRUE;
557 break;
558 }
559 entry = entry->next;
560 }
561 }
562#ifdef CHROMIUM_THREADSAFE
563 crUnlockMutex(&pHash->mutex);
564#endif
565
566 return rc;
567}
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