ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

hash.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.