1848b8605Smrg/**
2848b8605Smrg * \file hash.c
3848b8605Smrg * Generic hash table.
4848b8605Smrg *
5848b8605Smrg * Used for display lists, texture objects, vertex/fragment programs,
6848b8605Smrg * buffer objects, etc.  The hash functions are thread-safe.
7848b8605Smrg *
8848b8605Smrg * \note key=0 is illegal.
9848b8605Smrg *
10848b8605Smrg * \author Brian Paul
11848b8605Smrg */
12848b8605Smrg
13848b8605Smrg/*
14848b8605Smrg * Mesa 3-D graphics library
15848b8605Smrg *
16848b8605Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
17848b8605Smrg *
18848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
19848b8605Smrg * copy of this software and associated documentation files (the "Software"),
20848b8605Smrg * to deal in the Software without restriction, including without limitation
21848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
23848b8605Smrg * Software is furnished to do so, subject to the following conditions:
24848b8605Smrg *
25848b8605Smrg * The above copyright notice and this permission notice shall be included
26848b8605Smrg * in all copies or substantial portions of the Software.
27848b8605Smrg *
28848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
31848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
32848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
33848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
35848b8605Smrg */
36848b8605Smrg
37b8e80941Smrg#include "errors.h"
38848b8605Smrg#include "glheader.h"
39848b8605Smrg#include "hash.h"
40848b8605Smrg#include "util/hash_table.h"
41848b8605Smrg
42848b8605Smrg
43848b8605Smrg/**
44848b8605Smrg * Create a new hash table.
45848b8605Smrg *
46848b8605Smrg * \return pointer to a new, empty hash table.
47848b8605Smrg */
48848b8605Smrgstruct _mesa_HashTable *
49848b8605Smrg_mesa_NewHashTable(void)
50848b8605Smrg{
51848b8605Smrg   struct _mesa_HashTable *table = CALLOC_STRUCT(_mesa_HashTable);
52848b8605Smrg
53848b8605Smrg   if (table) {
54b8e80941Smrg      table->ht = _mesa_hash_table_create(NULL, uint_key_hash,
55b8e80941Smrg                                          uint_key_compare);
56848b8605Smrg      if (table->ht == NULL) {
57848b8605Smrg         free(table);
58848b8605Smrg         _mesa_error_no_memory(__func__);
59848b8605Smrg         return NULL;
60848b8605Smrg      }
61848b8605Smrg
62848b8605Smrg      _mesa_hash_table_set_deleted_key(table->ht, uint_key(DELETED_KEY_VALUE));
63b8e80941Smrg      /*
64b8e80941Smrg       * Needs to be recursive, since the callback in _mesa_HashWalk()
65b8e80941Smrg       * is allowed to call _mesa_HashRemove().
66b8e80941Smrg       */
67b8e80941Smrg      mtx_init(&table->Mutex, mtx_recursive);
68848b8605Smrg   }
69848b8605Smrg   else {
70848b8605Smrg      _mesa_error_no_memory(__func__);
71848b8605Smrg   }
72848b8605Smrg
73848b8605Smrg   return table;
74848b8605Smrg}
75848b8605Smrg
76848b8605Smrg
77848b8605Smrg
78848b8605Smrg/**
79848b8605Smrg * Delete a hash table.
80848b8605Smrg * Frees each entry on the hash table and then the hash table structure itself.
81848b8605Smrg * Note that the caller should have already traversed the table and deleted
82848b8605Smrg * the objects in the table (i.e. We don't free the entries' data pointer).
83848b8605Smrg *
84848b8605Smrg * \param table the hash table to delete.
85848b8605Smrg */
86848b8605Smrgvoid
87848b8605Smrg_mesa_DeleteHashTable(struct _mesa_HashTable *table)
88848b8605Smrg{
89848b8605Smrg   assert(table);
90848b8605Smrg
91848b8605Smrg   if (_mesa_hash_table_next_entry(table->ht, NULL) != NULL) {
92848b8605Smrg      _mesa_problem(NULL, "In _mesa_DeleteHashTable, found non-freed data");
93848b8605Smrg   }
94848b8605Smrg
95848b8605Smrg   _mesa_hash_table_destroy(table->ht, NULL);
96848b8605Smrg
97848b8605Smrg   mtx_destroy(&table->Mutex);
98848b8605Smrg   free(table);
99848b8605Smrg}
100848b8605Smrg
101848b8605Smrg
102848b8605Smrg
103848b8605Smrg/**
104848b8605Smrg * Lookup an entry in the hash table, without locking.
105848b8605Smrg * \sa _mesa_HashLookup
106848b8605Smrg */
107848b8605Smrgstatic inline void *
108848b8605Smrg_mesa_HashLookup_unlocked(struct _mesa_HashTable *table, GLuint key)
109848b8605Smrg{
110848b8605Smrg   const struct hash_entry *entry;
111848b8605Smrg
112848b8605Smrg   assert(table);
113848b8605Smrg   assert(key);
114848b8605Smrg
115848b8605Smrg   if (key == DELETED_KEY_VALUE)
116848b8605Smrg      return table->deleted_key_data;
117848b8605Smrg
118b8e80941Smrg   entry = _mesa_hash_table_search_pre_hashed(table->ht,
119b8e80941Smrg                                              uint_hash(key),
120b8e80941Smrg                                              uint_key(key));
121848b8605Smrg   if (!entry)
122848b8605Smrg      return NULL;
123848b8605Smrg
124848b8605Smrg   return entry->data;
125848b8605Smrg}
126848b8605Smrg
127848b8605Smrg
128848b8605Smrg/**
129848b8605Smrg * Lookup an entry in the hash table.
130848b8605Smrg *
131848b8605Smrg * \param table the hash table.
132848b8605Smrg * \param key the key.
133848b8605Smrg *
134848b8605Smrg * \return pointer to user's data or NULL if key not in table
135848b8605Smrg */
136848b8605Smrgvoid *
137848b8605Smrg_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
138848b8605Smrg{
139848b8605Smrg   void *res;
140b8e80941Smrg   _mesa_HashLockMutex(table);
141848b8605Smrg   res = _mesa_HashLookup_unlocked(table, key);
142b8e80941Smrg   _mesa_HashUnlockMutex(table);
143848b8605Smrg   return res;
144848b8605Smrg}
145848b8605Smrg
146848b8605Smrg
147848b8605Smrg/**
148848b8605Smrg * Lookup an entry in the hash table without locking the mutex.
149848b8605Smrg *
150848b8605Smrg * The hash table mutex must be locked manually by calling
151848b8605Smrg * _mesa_HashLockMutex() before calling this function.
152848b8605Smrg *
153848b8605Smrg * \param table the hash table.
154848b8605Smrg * \param key the key.
155848b8605Smrg *
156848b8605Smrg * \return pointer to user's data or NULL if key not in table
157848b8605Smrg */
158848b8605Smrgvoid *
159848b8605Smrg_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key)
160848b8605Smrg{
161848b8605Smrg   return _mesa_HashLookup_unlocked(table, key);
162848b8605Smrg}
163848b8605Smrg
164848b8605Smrg
165848b8605Smrgstatic inline void
166848b8605Smrg_mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data)
167848b8605Smrg{
168848b8605Smrg   uint32_t hash = uint_hash(key);
169848b8605Smrg   struct hash_entry *entry;
170848b8605Smrg
171848b8605Smrg   assert(table);
172848b8605Smrg   assert(key);
173848b8605Smrg
174848b8605Smrg   if (key > table->MaxKey)
175848b8605Smrg      table->MaxKey = key;
176848b8605Smrg
177848b8605Smrg   if (key == DELETED_KEY_VALUE) {
178848b8605Smrg      table->deleted_key_data = data;
179848b8605Smrg   } else {
180b8e80941Smrg      entry = _mesa_hash_table_search_pre_hashed(table->ht, hash, uint_key(key));
181848b8605Smrg      if (entry) {
182848b8605Smrg         entry->data = data;
183848b8605Smrg      } else {
184b8e80941Smrg         _mesa_hash_table_insert_pre_hashed(table->ht, hash, uint_key(key), data);
185848b8605Smrg      }
186848b8605Smrg   }
187848b8605Smrg}
188848b8605Smrg
189848b8605Smrg
190848b8605Smrg/**
191848b8605Smrg * Insert a key/pointer pair into the hash table without locking the mutex.
192848b8605Smrg * If an entry with this key already exists we'll replace the existing entry.
193848b8605Smrg *
194848b8605Smrg * The hash table mutex must be locked manually by calling
195848b8605Smrg * _mesa_HashLockMutex() before calling this function.
196848b8605Smrg *
197848b8605Smrg * \param table the hash table.
198848b8605Smrg * \param key the key (not zero).
199848b8605Smrg * \param data pointer to user data.
200848b8605Smrg */
201848b8605Smrgvoid
202848b8605Smrg_mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data)
203848b8605Smrg{
204848b8605Smrg   _mesa_HashInsert_unlocked(table, key, data);
205848b8605Smrg}
206848b8605Smrg
207848b8605Smrg
208848b8605Smrg/**
209848b8605Smrg * Insert a key/pointer pair into the hash table.
210848b8605Smrg * If an entry with this key already exists we'll replace the existing entry.
211848b8605Smrg *
212848b8605Smrg * \param table the hash table.
213848b8605Smrg * \param key the key (not zero).
214848b8605Smrg * \param data pointer to user data.
215848b8605Smrg */
216848b8605Smrgvoid
217848b8605Smrg_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
218848b8605Smrg{
219b8e80941Smrg   _mesa_HashLockMutex(table);
220848b8605Smrg   _mesa_HashInsert_unlocked(table, key, data);
221b8e80941Smrg   _mesa_HashUnlockMutex(table);
222848b8605Smrg}
223848b8605Smrg
224848b8605Smrg
225848b8605Smrg/**
226848b8605Smrg * Remove an entry from the hash table.
227848b8605Smrg *
228848b8605Smrg * \param table the hash table.
229848b8605Smrg * \param key key of entry to remove.
230848b8605Smrg *
231848b8605Smrg * While holding the hash table's lock, searches the entry with the matching
232848b8605Smrg * key and unlinks it.
233848b8605Smrg */
234b8e80941Smrgstatic inline void
235b8e80941Smrg_mesa_HashRemove_unlocked(struct _mesa_HashTable *table, GLuint key)
236848b8605Smrg{
237848b8605Smrg   struct hash_entry *entry;
238848b8605Smrg
239848b8605Smrg   assert(table);
240848b8605Smrg   assert(key);
241848b8605Smrg
242b8e80941Smrg   /* assert if _mesa_HashRemove illegally called from _mesa_HashDeleteAll
243b8e80941Smrg    * callback function. Have to check this outside of mutex lock.
244b8e80941Smrg    */
245b8e80941Smrg   assert(!table->InDeleteAll);
246848b8605Smrg
247848b8605Smrg   if (key == DELETED_KEY_VALUE) {
248848b8605Smrg      table->deleted_key_data = NULL;
249848b8605Smrg   } else {
250b8e80941Smrg      entry = _mesa_hash_table_search_pre_hashed(table->ht,
251b8e80941Smrg                                                 uint_hash(key),
252b8e80941Smrg                                                 uint_key(key));
253848b8605Smrg      _mesa_hash_table_remove(table->ht, entry);
254848b8605Smrg   }
255848b8605Smrg}
256848b8605Smrg
257848b8605Smrg
258b8e80941Smrgvoid
259b8e80941Smrg_mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key)
260b8e80941Smrg{
261b8e80941Smrg   _mesa_HashRemove_unlocked(table, key);
262b8e80941Smrg}
263b8e80941Smrg
264b8e80941Smrgvoid
265b8e80941Smrg_mesa_HashRemove(struct _mesa_HashTable *table, GLuint key)
266b8e80941Smrg{
267b8e80941Smrg   _mesa_HashLockMutex(table);
268b8e80941Smrg   _mesa_HashRemove_unlocked(table, key);
269b8e80941Smrg   _mesa_HashUnlockMutex(table);
270b8e80941Smrg}
271848b8605Smrg
272848b8605Smrg/**
273848b8605Smrg * Delete all entries in a hash table, but don't delete the table itself.
274848b8605Smrg * Invoke the given callback function for each table entry.
275848b8605Smrg *
276848b8605Smrg * \param table  the hash table to delete
277848b8605Smrg * \param callback  the callback function
278848b8605Smrg * \param userData  arbitrary pointer to pass along to the callback
279848b8605Smrg *                  (this is typically a struct gl_context pointer)
280848b8605Smrg */
281848b8605Smrgvoid
282848b8605Smrg_mesa_HashDeleteAll(struct _mesa_HashTable *table,
283848b8605Smrg                    void (*callback)(GLuint key, void *data, void *userData),
284848b8605Smrg                    void *userData)
285848b8605Smrg{
286b8e80941Smrg   assert(callback);
287b8e80941Smrg   _mesa_HashLockMutex(table);
288848b8605Smrg   table->InDeleteAll = GL_TRUE;
289848b8605Smrg   hash_table_foreach(table->ht, entry) {
290848b8605Smrg      callback((uintptr_t)entry->key, entry->data, userData);
291848b8605Smrg      _mesa_hash_table_remove(table->ht, entry);
292848b8605Smrg   }
293848b8605Smrg   if (table->deleted_key_data) {
294848b8605Smrg      callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
295848b8605Smrg      table->deleted_key_data = NULL;
296848b8605Smrg   }
297848b8605Smrg   table->InDeleteAll = GL_FALSE;
298b8e80941Smrg   _mesa_HashUnlockMutex(table);
299848b8605Smrg}
300848b8605Smrg
301848b8605Smrg
302848b8605Smrg/**
303b8e80941Smrg * Walk over all entries in a hash table, calling callback function for each.
304b8e80941Smrg * \param table  the hash table to walk
305b8e80941Smrg * \param callback  the callback function
306b8e80941Smrg * \param userData  arbitrary pointer to pass along to the callback
307b8e80941Smrg *                  (this is typically a struct gl_context pointer)
308848b8605Smrg */
309b8e80941Smrgstatic void
310b8e80941Smrghash_walk_unlocked(const struct _mesa_HashTable *table,
311b8e80941Smrg                   void (*callback)(GLuint key, void *data, void *userData),
312b8e80941Smrg                   void *userData)
313848b8605Smrg{
314b8e80941Smrg   assert(table);
315b8e80941Smrg   assert(callback);
316848b8605Smrg
317848b8605Smrg   hash_table_foreach(table->ht, entry) {
318b8e80941Smrg      callback((uintptr_t)entry->key, entry->data, userData);
319848b8605Smrg   }
320b8e80941Smrg   if (table->deleted_key_data)
321b8e80941Smrg      callback(DELETED_KEY_VALUE, table->deleted_key_data, userData);
322848b8605Smrg}
323848b8605Smrg
324848b8605Smrg
325848b8605Smrgvoid
326848b8605Smrg_mesa_HashWalk(const struct _mesa_HashTable *table,
327848b8605Smrg               void (*callback)(GLuint key, void *data, void *userData),
328848b8605Smrg               void *userData)
329848b8605Smrg{
330848b8605Smrg   /* cast-away const */
331848b8605Smrg   struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table;
332848b8605Smrg
333b8e80941Smrg   _mesa_HashLockMutex(table2);
334b8e80941Smrg   hash_walk_unlocked(table, callback, userData);
335b8e80941Smrg   _mesa_HashUnlockMutex(table2);
336b8e80941Smrg}
337b8e80941Smrg
338b8e80941Smrgvoid
339b8e80941Smrg_mesa_HashWalkLocked(const struct _mesa_HashTable *table,
340b8e80941Smrg               void (*callback)(GLuint key, void *data, void *userData),
341b8e80941Smrg               void *userData)
342b8e80941Smrg{
343b8e80941Smrg   hash_walk_unlocked(table, callback, userData);
344848b8605Smrg}
345848b8605Smrg
346848b8605Smrgstatic void
347848b8605Smrgdebug_print_entry(GLuint key, void *data, void *userData)
348848b8605Smrg{
349848b8605Smrg   _mesa_debug(NULL, "%u %p\n", key, data);
350848b8605Smrg}
351848b8605Smrg
352848b8605Smrg/**
353848b8605Smrg * Dump contents of hash table for debugging.
354848b8605Smrg *
355848b8605Smrg * \param table the hash table.
356848b8605Smrg */
357848b8605Smrgvoid
358848b8605Smrg_mesa_HashPrint(const struct _mesa_HashTable *table)
359848b8605Smrg{
360848b8605Smrg   if (table->deleted_key_data)
361848b8605Smrg      debug_print_entry(DELETED_KEY_VALUE, table->deleted_key_data, NULL);
362848b8605Smrg   _mesa_HashWalk(table, debug_print_entry, NULL);
363848b8605Smrg}
364848b8605Smrg
365848b8605Smrg
366848b8605Smrg/**
367848b8605Smrg * Find a block of adjacent unused hash keys.
368848b8605Smrg *
369848b8605Smrg * \param table the hash table.
370848b8605Smrg * \param numKeys number of keys needed.
371848b8605Smrg *
372848b8605Smrg * \return Starting key of free block or 0 if failure.
373848b8605Smrg *
374848b8605Smrg * If there are enough free keys between the maximum key existing in the table
375848b8605Smrg * (_mesa_HashTable::MaxKey) and the maximum key possible, then simply return
376848b8605Smrg * the adjacent key. Otherwise do a full search for a free key block in the
377848b8605Smrg * allowable key range.
378848b8605Smrg */
379848b8605SmrgGLuint
380848b8605Smrg_mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys)
381848b8605Smrg{
382848b8605Smrg   const GLuint maxKey = ~((GLuint) 0) - 1;
383848b8605Smrg   if (maxKey - numKeys > table->MaxKey) {
384848b8605Smrg      /* the quick solution */
385848b8605Smrg      return table->MaxKey + 1;
386848b8605Smrg   }
387848b8605Smrg   else {
388848b8605Smrg      /* the slow solution */
389848b8605Smrg      GLuint freeCount = 0;
390848b8605Smrg      GLuint freeStart = 1;
391848b8605Smrg      GLuint key;
392848b8605Smrg      for (key = 1; key != maxKey; key++) {
393848b8605Smrg	 if (_mesa_HashLookup_unlocked(table, key)) {
394848b8605Smrg	    /* darn, this key is already in use */
395848b8605Smrg	    freeCount = 0;
396848b8605Smrg	    freeStart = key+1;
397848b8605Smrg	 }
398848b8605Smrg	 else {
399848b8605Smrg	    /* this key not in use, check if we've found enough */
400848b8605Smrg	    freeCount++;
401848b8605Smrg	    if (freeCount == numKeys) {
402848b8605Smrg	       return freeStart;
403848b8605Smrg	    }
404848b8605Smrg	 }
405848b8605Smrg      }
406848b8605Smrg      /* cannot allocate a block of numKeys consecutive keys */
407848b8605Smrg      return 0;
408848b8605Smrg   }
409848b8605Smrg}
410848b8605Smrg
411848b8605Smrg
412848b8605Smrg/**
413848b8605Smrg * Return the number of entries in the hash table.
414848b8605Smrg */
415848b8605SmrgGLuint
416848b8605Smrg_mesa_HashNumEntries(const struct _mesa_HashTable *table)
417848b8605Smrg{
418848b8605Smrg   GLuint count = 0;
419848b8605Smrg
420848b8605Smrg   if (table->deleted_key_data)
421848b8605Smrg      count++;
422848b8605Smrg
423b8e80941Smrg   count += _mesa_hash_table_num_entries(table->ht);
424848b8605Smrg
425848b8605Smrg   return count;
426848b8605Smrg}
427