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
Line 
1/* $Id: hash.c,v 1.3 2000-05-23 20:40:36 jeroen Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.3
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
31#include "glheader.h"
32#include "macros.h"
33#include "hash.h"
34#include "mem.h"
35#include "glthread.h"
36#endif
37
38
39/*
40 * Generic hash table.
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
55struct _mesa_HashTable {
56 struct HashEntry *Table[TABLE_SIZE];
57 GLuint MaxKey;
58 _glthread_Mutex Mutex;
59};
60
61
62
63/*
64 * Return pointer to a new, empty hash table.
65 */
66struct _mesa_HashTable *_mesa_NewHashTable(void)
67{
68 return CALLOC_STRUCT(_mesa_HashTable);
69}
70
71
72
73/*
74 * Delete a hash table.
75 */
76void _mesa_DeleteHashTable(struct _mesa_HashTable *table)
77{
78 GLuint i;
79 ASSERT(table);
80 for (i=0;i<TABLE_SIZE;i++) {
81 struct HashEntry *entry = table->Table[i];
82 while (entry) {
83 struct HashEntry *next = entry->Next;
84 FREE(entry);
85 entry = next;
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 */
99void *_mesa_HashLookup(const struct _mesa_HashTable *table, GLuint key)
100{
101 GLuint pos;
102 const struct HashEntry *entry;
103
104 ASSERT(table);
105 ASSERT(key);
106
107 pos = key & (TABLE_SIZE-1);
108 entry = table->Table[pos];
109 while (entry) {
110 if (entry->Key == key) {
111 return entry->Data;
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 */
127void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
128{
129 /* search for existing entry with this key */
130 GLuint pos;
131 struct HashEntry *entry;
132
133 ASSERT(table);
134 ASSERT(key);
135
136 _glthread_LOCK_MUTEX(table->Mutex);
137
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 */
146 entry->Data = data;
147 _glthread_UNLOCK_MUTEX(table->Mutex);
148 return;
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;
159
160 _glthread_UNLOCK_MUTEX(table->Mutex);
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 */
170void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
171{
172 GLuint pos;
173 struct HashEntry *entry, *prev;
174
175 ASSERT(table);
176 ASSERT(key);
177
178 _glthread_LOCK_MUTEX(table->Mutex);
179
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);
193 _glthread_UNLOCK_MUTEX(table->Mutex);
194 return;
195 }
196 prev = entry;
197 entry = entry->Next;
198 }
199
200 _glthread_UNLOCK_MUTEX(table->Mutex);
201}
202
203
204
205/*
206 * Return the key of the "first" entry in the hash table.
207 * This is used in the course of deleting all display lists when
208 * a context is destroyed.
209 */
210GLuint _mesa_HashFirstEntry(struct _mesa_HashTable *table)
211{
212 GLuint pos;
213 ASSERT(table);
214 _glthread_LOCK_MUTEX(table->Mutex);
215 for (pos=0; pos < TABLE_SIZE; pos++) {
216 if (table->Table[pos]) {
217 _glthread_UNLOCK_MUTEX(table->Mutex);
218 return table->Table[pos]->Key;
219 }
220 }
221 _glthread_UNLOCK_MUTEX(table->Mutex);
222 return 0;
223}
224
225
226
227/*
228 * Dump contents of hash table for debugging.
229 */
230void _mesa_HashPrint(const struct _mesa_HashTable *table)
231{
232 GLuint i;
233 ASSERT(table);
234 for (i=0;i<TABLE_SIZE;i++) {
235 const struct HashEntry *entry = table->Table[i];
236 while (entry) {
237 printf("%u %p\n", entry->Key, entry->Data);
238 entry = entry->Next;
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
249 * Return: starting key of free block or 0 if failure
250 */
251GLuint _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
252{
253 GLuint maxKey = ~((GLuint) 0);
254 _glthread_LOCK_MUTEX(table->Mutex);
255 if (maxKey - numKeys > table->MaxKey) {
256 /* the quick solution */
257 _glthread_UNLOCK_MUTEX(table->Mutex);
258 return table->MaxKey + 1;
259 }
260 else {
261 /* the slow solution */
262 GLuint freeCount = 0;
263 GLuint freeStart = 1;
264 GLuint key;
265 for (key=1; key!=maxKey; key++) {
266 if (_mesa_HashLookup(table, key)) {
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) {
275 _glthread_UNLOCK_MUTEX(table->Mutex);
276 return freeStart;
277 }
278 }
279 }
280 /* cannot allocate a block of numKeys consecutive keys */
281 _glthread_UNLOCK_MUTEX(table->Mutex);
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
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);
306
307 return 0;
308}
309#endif
Note: See TracBrowser for help on using the repository browser.