source: trunk/src/opengl/mesa/hash.c

Last change on this file was 3598, checked in by jeroen, 25 years ago

* empty log message *

File size: 7.1 KB
RevLine 
[3598]1/* $Id: hash.c,v 1.3 2000-05-23 20:40:36 jeroen Exp $ */
[2938]2
3/*
4 * Mesa 3-D graphics library
[3598]5 * Version: 3.3
[2938]6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#ifdef PC_HEADER
29#include "all.h"
30#else
[3598]31#include "glheader.h"
32#include "macros.h"
[2938]33#include "hash.h"
[3598]34#include "mem.h"
35#include "glthread.h"
[2938]36#endif
37
38
39/*
[3598]40 * Generic hash table.
[2938]41 *
42 * This is used to implement display list and texture object lookup.
43 * NOTE: key=0 is illegal.
44 */
45
46
47#define TABLE_SIZE 1024
48
49struct HashEntry {
50 GLuint Key;
51 void *Data;
52 struct HashEntry *Next;
53};
54
[3598]55struct _mesa_HashTable {
[2938]56 struct HashEntry *Table[TABLE_SIZE];
57 GLuint MaxKey;
[3598]58 _glthread_Mutex Mutex;
[2938]59};
60
61
62
63/*
64 * Return pointer to a new, empty hash table.
65 */
[3598]66struct _mesa_HashTable *_mesa_NewHashTable(void)
[2938]67{
[3598]68 return CALLOC_STRUCT(_mesa_HashTable);
[2938]69}
70
71
72
73/*
74 * Delete a hash table.
75 */
[3598]76void _mesa_DeleteHashTable(struct _mesa_HashTable *table)
[2938]77{
78 GLuint i;
[3598]79 ASSERT(table);
[2938]80 for (i=0;i<TABLE_SIZE;i++) {
81 struct HashEntry *entry = table->Table[i];
82 while (entry) {
[2962]83 struct HashEntry *next = entry->Next;
84 FREE(entry);
85 entry = next;
[2938]86 }
87 }
88 FREE(table);
89}
90
91
92
93/*
94 * Lookup an entry in the hash table.
95 * Input: table - the hash table
96 * key - the key
97 * Return: user data pointer or NULL if key not in table
98 */
[3598]99void *_mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key)
[2938]100{
101 GLuint pos;
102 const struct HashEntry *entry;
103
[3598]104 ASSERT(table);
105 ASSERT(key);
106
[2938]107 pos = key & (TABLE_SIZE-1);
108 entry = table->Table[pos];
109 while (entry) {
110 if (entry->Key == key) {
[2962]111 return entry->Data;
[2938]112 }
113 entry = entry->Next;
114 }
115 return NULL;
116}
117
118
119
120/*
121 * Insert into the hash table. If an entry with this key already exists
122 * we'll replace the existing entry.
123 * Input: table - the hash table
124 * key - the key (not zero)
125 * data - pointer to user data
126 */
[3598]127void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
[2938]128{
129 /* search for existing entry with this key */
130 GLuint pos;
131 struct HashEntry *entry;
132
[3598]133 ASSERT(table);
134 ASSERT(key);
[2938]135
[3598]136 _glthread_LOCK_MUTEX(table->Mutex);
137
[2938]138 if (key > table->MaxKey)
139 table->MaxKey = key;
140
141 pos = key & (TABLE_SIZE-1);
142 entry = table->Table[pos];
143 while (entry) {
144 if (entry->Key == key) {
145 /* replace entry's data */
[2962]146 entry->Data = data;
[3598]147 _glthread_UNLOCK_MUTEX(table->Mutex);
[2962]148 return;
[2938]149 }
150 entry = entry->Next;
151 }
152
153 /* alloc and insert new table entry */
154 entry = MALLOC_STRUCT(HashEntry);
155 entry->Key = key;
156 entry->Data = data;
157 entry->Next = table->Table[pos];
158 table->Table[pos] = entry;
[3598]159
160 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]161}
162
163
164
165/*
166 * Remove an entry from the hash table.
167 * Input: table - the hash table
168 * key - key of entry to remove
169 */
[3598]170void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
[2938]171{
172 GLuint pos;
173 struct HashEntry *entry, *prev;
174
[3598]175 ASSERT(table);
176 ASSERT(key);
[2938]177
[3598]178 _glthread_LOCK_MUTEX(table->Mutex);
179
[2938]180 pos = key & (TABLE_SIZE-1);
181 prev = NULL;
182 entry = table->Table[pos];
183 while (entry) {
184 if (entry->Key == key) {
185 /* found it! */
186 if (prev) {
187 prev->Next = entry->Next;
188 }
189 else {
190 table->Table[pos] = entry->Next;
191 }
192 FREE(entry);
[3598]193 _glthread_UNLOCK_MUTEX(table->Mutex);
[2962]194 return;
[2938]195 }
196 prev = entry;
197 entry = entry->Next;
198 }
[3598]199
200 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]201}
202
203
204
205/*
206 * Return the key of the "first" entry in the hash table.
[3598]207 * This is used in the course of deleting all display lists when
208 * a context is destroyed.
[2938]209 */
[3598]210GLuint _mesa_HashFirstEntry(struct _mesa_HashTable *table)
[2938]211{
212 GLuint pos;
[3598]213 ASSERT(table);
214 _glthread_LOCK_MUTEX(table->Mutex);
[2938]215 for (pos=0; pos < TABLE_SIZE; pos++) {
[3598]216 if (table->Table[pos]) {
217 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]218 return table->Table[pos]->Key;
[3598]219 }
[2938]220 }
[3598]221 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]222 return 0;
223}
224
225
226
227/*
228 * Dump contents of hash table for debugging.
229 */
[3598]230void _mesa_HashPrint(const struct _mesa_HashTable *table)
[2938]231{
232 GLuint i;
[3598]233 ASSERT(table);
[2938]234 for (i=0;i<TABLE_SIZE;i++) {
235 const struct HashEntry *entry = table->Table[i];
236 while (entry) {
[2962]237 printf("%u %p\n", entry->Key, entry->Data);
238 entry = entry->Next;
[2938]239 }
240 }
241}
242
243
244
245/*
246 * Find a block of 'numKeys' adjacent unused hash keys.
247 * Input: table - the hash table
248 * numKeys - number of keys needed
[3598]249 * Return: starting key of free block or 0 if failure
[2938]250 */
[3598]251GLuint _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
[2938]252{
253 GLuint maxKey = ~((GLuint) 0);
[3598]254 _glthread_LOCK_MUTEX(table->Mutex);
[2938]255 if (maxKey - numKeys > table->MaxKey) {
256 /* the quick solution */
[3598]257 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]258 return table->MaxKey + 1;
259 }
260 else {
261 /* the slow solution */
262 GLuint freeCount = 0;
[3598]263 GLuint freeStart = 1;
[2938]264 GLuint key;
[3598]265 for (key=1; key!=maxKey; key++) {
266 if (_mesa_HashLookup(table, key)) {
[2962]267 /* darn, this key is already in use */
268 freeCount = 0;
269 freeStart = key+1;
270 }
271 else {
272 /* this key not in use, check if we've found enough */
273 freeCount++;
274 if (freeCount == numKeys) {
[3598]275 _glthread_UNLOCK_MUTEX(table->Mutex);
[2962]276 return freeStart;
277 }
278 }
[2938]279 }
280 /* cannot allocate a block of numKeys consecutive keys */
[3598]281 _glthread_UNLOCK_MUTEX(table->Mutex);
[2938]282 return 0;
283 }
284}
285
286
287
288#ifdef HASH_TEST_HARNESS
289int main(int argc, char *argv[])
290{
291 int a, b, c;
292 struct HashTable *t;
293
294 printf("&a = %p\n", &a);
295 printf("&b = %p\n", &b);
296
[3598]297 t = _mesa_NewHashTable();
298 _mesa_HashInsert(t, 501, &a);
299 _mesa_HashInsert(t, 10, &c);
300 _mesa_HashInsert(t, 0xfffffff8, &b);
301 _mesa_HashPrint(t);
302 printf("Find 501: %p\n", _mesa_HashLookup(t,501));
303 printf("Find 1313: %p\n", _mesa_HashLookup(t,1313));
304 printf("Find block of 100: %d\n", _mesa_HashFindFreeKeyBlock(t, 100));
305 _mesa_DeleteHashTable(t);
[2938]306
307 return 0;
308}
309#endif
Note: See TracBrowser for help on using the repository browser.