Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhash.c
Go to the documentation of this file.
00001 00013 /* 00014 * Mesa 3-D graphics library 00015 * Version: 6.5.1 00016 * 00017 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 00018 * 00019 * Permission is hereby granted, free of charge, to any person obtaining a 00020 * copy of this software and associated documentation files (the "Software"), 00021 * to deal in the Software without restriction, including without limitation 00022 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00023 * and/or sell copies of the Software, and to permit persons to whom the 00024 * Software is furnished to do so, subject to the following conditions: 00025 * 00026 * The above copyright notice and this permission notice shall be included 00027 * in all copies or substantial portions of the Software. 00028 * 00029 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00030 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00031 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00032 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00033 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00034 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00035 */ 00036 00037 00038 #include "glheader.h" 00039 #include "imports.h" 00040 #include "glapi/glthread.h" 00041 #include "hash.h" 00042 00043 00044 #define TABLE_SIZE 1023 00046 #define HASH_FUNC(K) ((K) % TABLE_SIZE) 00047 00048 00052 struct HashEntry { 00053 GLuint Key; 00054 void *Data; 00055 struct HashEntry *Next; 00056 }; 00057 00058 00062 struct _mesa_HashTable { 00063 struct HashEntry *Table[TABLE_SIZE]; 00064 GLuint MaxKey; 00065 _glthread_Mutex Mutex; 00066 GLboolean InDeleteAll; 00067 }; 00068 00069 00070 00076 struct _mesa_HashTable * 00077 _mesa_NewHashTable(void) 00078 { 00079 struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable); 00080 if (table) { 00081 _glthread_INIT_MUTEX(table->Mutex); 00082 } 00083 return table; 00084 } 00085 00086 00087 00096 void 00097 _mesa_DeleteHashTable(struct _mesa_HashTable *table) 00098 { 00099 GLuint pos; 00100 assert(table); 00101 for (pos = 0; pos < TABLE_SIZE; pos++) { 00102 struct HashEntry *entry = table->Table[pos]; 00103 while (entry) { 00104 struct HashEntry *next = entry->Next; 00105 if (entry->Data) { 00106 _mesa_problem(NULL, 00107 "In _mesa_DeleteHashTable, found non-freed data"); 00108 } 00109 _mesa_free(entry); 00110 entry = next; 00111 } 00112 } 00113 _glthread_DESTROY_MUTEX(table->Mutex); 00114 _mesa_free(table); 00115 } 00116 00117 00118 00127 void * 00128 _mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key) 00129 { 00130 GLuint pos; 00131 const struct HashEntry *entry; 00132 00133 assert(table); 00134 assert(key); 00135 00136 pos = HASH_FUNC(key); 00137 entry = table->Table[pos]; 00138 while (entry) { 00139 if (entry->Key == key) { 00140 return entry->Data; 00141 } 00142 entry = entry->Next; 00143 } 00144 return NULL; 00145 } 00146 00147 00148 00157 void 00158 _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) 00159 { 00160 /* search for existing entry with this key */ 00161 GLuint pos; 00162 struct HashEntry *entry; 00163 00164 assert(table); 00165 assert(key); 00166 00167 _glthread_LOCK_MUTEX(table->Mutex); 00168 00169 if (key > table->MaxKey) 00170 table->MaxKey = key; 00171 00172 pos = HASH_FUNC(key); 00173 00174 /* check if replacing an existing entry with same key */ 00175 for (entry = table->Table[pos]; entry; entry = entry->Next) { 00176 if (entry->Key == key) { 00177 /* replace entry's data */ 00178 #if 0 /* not sure this check is always valid */ 00179 if (entry->Data) { 00180 _mesa_problem(NULL, "Memory leak detected in _mesa_HashInsert"); 00181 } 00182 #endif 00183 entry->Data = data; 00184 _glthread_UNLOCK_MUTEX(table->Mutex); 00185 return; 00186 } 00187 } 00188 00189 /* alloc and insert new table entry */ 00190 entry = MALLOC_STRUCT(HashEntry); 00191 entry->Key = key; 00192 entry->Data = data; 00193 entry->Next = table->Table[pos]; 00194 table->Table[pos] = entry; 00195 00196 _glthread_UNLOCK_MUTEX(table->Mutex); 00197 } 00198 00199 00200 00210 void 00211 _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) 00212 { 00213 GLuint pos; 00214 struct HashEntry *entry, *prev; 00215 00216 assert(table); 00217 assert(key); 00218 00219 /* have to check this outside of mutex lock */ 00220 if (table->InDeleteAll) { 00221 _mesa_problem(NULL, "_mesa_HashRemove illegally called from " 00222 "_mesa_HashDeleteAll callback function"); 00223 return; 00224 } 00225 00226 _glthread_LOCK_MUTEX(table->Mutex); 00227 00228 pos = HASH_FUNC(key); 00229 prev = NULL; 00230 entry = table->Table[pos]; 00231 while (entry) { 00232 if (entry->Key == key) { 00233 /* found it! */ 00234 if (prev) { 00235 prev->Next = entry->Next; 00236 } 00237 else { 00238 table->Table[pos] = entry->Next; 00239 } 00240 _mesa_free(entry); 00241 _glthread_UNLOCK_MUTEX(table->Mutex); 00242 return; 00243 } 00244 prev = entry; 00245 entry = entry->Next; 00246 } 00247 00248 _glthread_UNLOCK_MUTEX(table->Mutex); 00249 } 00250 00251 00252 00262 void 00263 _mesa_HashDeleteAll(struct _mesa_HashTable *table, 00264 void (*callback)(GLuint key, void *data, void *userData), 00265 void *userData) 00266 { 00267 GLuint pos; 00268 ASSERT(table); 00269 ASSERT(callback); 00270 _glthread_LOCK_MUTEX(table->Mutex); 00271 table->InDeleteAll = GL_TRUE; 00272 for (pos = 0; pos < TABLE_SIZE; pos++) { 00273 struct HashEntry *entry, *next; 00274 for (entry = table->Table[pos]; entry; entry = next) { 00275 callback(entry->Key, entry->Data, userData); 00276 next = entry->Next; 00277 _mesa_free(entry); 00278 } 00279 table->Table[pos] = NULL; 00280 } 00281 table->InDeleteAll = GL_FALSE; 00282 _glthread_UNLOCK_MUTEX(table->Mutex); 00283 } 00284 00285 00293 void 00294 _mesa_HashWalk(const struct _mesa_HashTable *table, 00295 void (*callback)(GLuint key, void *data, void *userData), 00296 void *userData) 00297 { 00298 /* cast-away const */ 00299 struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table; 00300 GLuint pos; 00301 ASSERT(table); 00302 ASSERT(callback); 00303 _glthread_LOCK_MUTEX(table2->Mutex); 00304 for (pos = 0; pos < TABLE_SIZE; pos++) { 00305 struct HashEntry *entry; 00306 for (entry = table->Table[pos]; entry; entry = entry->Next) { 00307 callback(entry->Key, entry->Data, userData); 00308 } 00309 } 00310 _glthread_UNLOCK_MUTEX(table2->Mutex); 00311 } 00312 00313 00322 GLuint 00323 _mesa_HashFirstEntry(struct _mesa_HashTable *table) 00324 { 00325 GLuint pos; 00326 assert(table); 00327 _glthread_LOCK_MUTEX(table->Mutex); 00328 for (pos = 0; pos < TABLE_SIZE; pos++) { 00329 if (table->Table[pos]) { 00330 _glthread_UNLOCK_MUTEX(table->Mutex); 00331 return table->Table[pos]->Key; 00332 } 00333 } 00334 _glthread_UNLOCK_MUTEX(table->Mutex); 00335 return 0; 00336 } 00337 00338 00345 GLuint 00346 _mesa_HashNextEntry(const struct _mesa_HashTable *table, GLuint key) 00347 { 00348 const struct HashEntry *entry; 00349 GLuint pos; 00350 00351 assert(table); 00352 assert(key); 00353 00354 /* Find the entry with given key */ 00355 pos = HASH_FUNC(key); 00356 for (entry = table->Table[pos]; entry ; entry = entry->Next) { 00357 if (entry->Key == key) { 00358 break; 00359 } 00360 } 00361 00362 if (!entry) { 00363 /* the given key was not found, so we can't find the next entry */ 00364 return 0; 00365 } 00366 00367 if (entry->Next) { 00368 /* return next in linked list */ 00369 return entry->Next->Key; 00370 } 00371 else { 00372 /* look for next non-empty table slot */ 00373 pos++; 00374 while (pos < TABLE_SIZE) { 00375 if (table->Table[pos]) { 00376 return table->Table[pos]->Key; 00377 } 00378 pos++; 00379 } 00380 return 0; 00381 } 00382 } 00383 00384 00390 void 00391 _mesa_HashPrint(const struct _mesa_HashTable *table) 00392 { 00393 GLuint pos; 00394 assert(table); 00395 for (pos = 0; pos < TABLE_SIZE; pos++) { 00396 const struct HashEntry *entry = table->Table[pos]; 00397 while (entry) { 00398 _mesa_debug(NULL, "%u %p\n", entry->Key, entry->Data); 00399 entry = entry->Next; 00400 } 00401 } 00402 } 00403 00404 00405 00419 GLuint 00420 _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys) 00421 { 00422 const GLuint maxKey = ~((GLuint) 0); 00423 _glthread_LOCK_MUTEX(table->Mutex); 00424 if (maxKey - numKeys > table->MaxKey) { 00425 /* the quick solution */ 00426 _glthread_UNLOCK_MUTEX(table->Mutex); 00427 return table->MaxKey + 1; 00428 } 00429 else { 00430 /* the slow solution */ 00431 GLuint freeCount = 0; 00432 GLuint freeStart = 1; 00433 GLuint key; 00434 for (key = 1; key != maxKey; key++) { 00435 if (_mesa_HashLookup(table, key)) { 00436 /* darn, this key is already in use */ 00437 freeCount = 0; 00438 freeStart = key+1; 00439 } 00440 else { 00441 /* this key not in use, check if we've found enough */ 00442 freeCount++; 00443 if (freeCount == numKeys) { 00444 _glthread_UNLOCK_MUTEX(table->Mutex); 00445 return freeStart; 00446 } 00447 } 00448 } 00449 /* cannot allocate a block of numKeys consecutive keys */ 00450 _glthread_UNLOCK_MUTEX(table->Mutex); 00451 return 0; 00452 } 00453 } 00454 00455 00456 #if 0 /* debug only */ 00457 00461 static void 00462 test_hash_walking(void) 00463 { 00464 struct _mesa_HashTable *t = _mesa_NewHashTable(); 00465 const GLuint limit = 50000; 00466 GLuint i; 00467 00468 /* create some entries */ 00469 for (i = 0; i < limit; i++) { 00470 GLuint dummy; 00471 GLuint k = (rand() % (limit * 10)) + 1; 00472 while (_mesa_HashLookup(t, k)) { 00473 /* id already in use, try another */ 00474 k = (rand() % (limit * 10)) + 1; 00475 } 00476 _mesa_HashInsert(t, k, &dummy); 00477 } 00478 00479 /* walk over all entries */ 00480 { 00481 GLuint k = _mesa_HashFirstEntry(t); 00482 GLuint count = 0; 00483 while (k) { 00484 GLuint knext = _mesa_HashNextEntry(t, k); 00485 assert(knext != k); 00486 _mesa_HashRemove(t, k); 00487 count++; 00488 k = knext; 00489 } 00490 assert(count == limit); 00491 k = _mesa_HashFirstEntry(t); 00492 assert(k==0); 00493 } 00494 00495 _mesa_DeleteHashTable(t); 00496 } 00497 00498 00499 void 00500 _mesa_test_hash_functions(void) 00501 { 00502 int a, b, c; 00503 struct _mesa_HashTable *t; 00504 00505 t = _mesa_NewHashTable(); 00506 _mesa_HashInsert(t, 501, &a); 00507 _mesa_HashInsert(t, 10, &c); 00508 _mesa_HashInsert(t, 0xfffffff8, &b); 00509 /*_mesa_HashPrint(t);*/ 00510 00511 assert(_mesa_HashLookup(t,501)); 00512 assert(!_mesa_HashLookup(t,1313)); 00513 assert(_mesa_HashFindFreeKeyBlock(t, 100)); 00514 00515 _mesa_DeleteHashTable(t); 00516 00517 test_hash_walking(); 00518 } 00519 00520 #endif Generated on Sat May 26 2012 04:19:04 for ReactOS by
1.7.6.1
|