17117f1b4Smrg/**
27117f1b4Smrg * \file hash.h
37ec681f3Smrg * Generic hash table.
47117f1b4Smrg */
57117f1b4Smrg
67117f1b4Smrg/*
77117f1b4Smrg * Mesa 3-D graphics library
87117f1b4Smrg *
97117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
107117f1b4Smrg *
117117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
127117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
137117f1b4Smrg * to deal in the Software without restriction, including without limitation
147117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
157117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
167117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
177117f1b4Smrg *
187117f1b4Smrg * The above copyright notice and this permission notice shall be included
197117f1b4Smrg * in all copies or substantial portions of the Software.
207117f1b4Smrg *
217117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
227117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
237117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
287117f1b4Smrg */
297117f1b4Smrg
307117f1b4Smrg
317117f1b4Smrg#ifndef HASH_H
327117f1b4Smrg#define HASH_H
337117f1b4Smrg
347117f1b4Smrg
357ec681f3Smrg#include <stdbool.h>
367ec681f3Smrg#include <stdint.h>
377117f1b4Smrg#include "glheader.h"
387ec681f3Smrg
3901e04c3fSmrg#include "c11/threads.h"
407ec681f3Smrg#include "util/simple_mtx.h"
417ec681f3Smrg
427ec681f3Smrgstruct util_idalloc;
437117f1b4Smrg
4401e04c3fSmrg/**
4501e04c3fSmrg * Magic GLuint object name that gets stored outside of the struct hash_table.
4601e04c3fSmrg *
4701e04c3fSmrg * The hash table needs a particular pointer to be the marker for a key that
4801e04c3fSmrg * was deleted from the table, along with NULL for the "never allocated in the
4901e04c3fSmrg * table" marker.  Legacy GL allows any GLuint to be used as a GL object name,
5001e04c3fSmrg * and we use a 1:1 mapping from GLuints to key pointers, so we need to be
5101e04c3fSmrg * able to track a GLuint that happens to match the deleted key outside of
5201e04c3fSmrg * struct hash_table.  We tell the hash table to use "1" as the deleted key
5301e04c3fSmrg * value, so that we test the deleted-key-in-the-table path as best we can.
5401e04c3fSmrg */
5501e04c3fSmrg#define DELETED_KEY_VALUE 1
5601e04c3fSmrg
5701e04c3fSmrg/** @{
5801e04c3fSmrg * Mapping from our use of GLuint as both the key and the hash value to the
5901e04c3fSmrg * hash_table.h API
6001e04c3fSmrg *
6101e04c3fSmrg * There exist many integer hash functions, designed to avoid collisions when
6201e04c3fSmrg * the integers are spread across key space with some patterns.  In GL, the
6301e04c3fSmrg * pattern (in the case of glGen*()ed object IDs) is that the keys are unique
6401e04c3fSmrg * contiguous integers starting from 1.  Because of that, we just use the key
6501e04c3fSmrg * as the hash value, to minimize the cost of the hash function.  If objects
6601e04c3fSmrg * are never deleted, we will never see a collision in the table, because the
6701e04c3fSmrg * table resizes itself when it approaches full, and thus key % table_size ==
6801e04c3fSmrg * key.
6901e04c3fSmrg *
7001e04c3fSmrg * The case where we could have collisions for genned objects would be
7101e04c3fSmrg * something like: glGenBuffers(&a, 100); glDeleteBuffers(&a + 50, 50);
7201e04c3fSmrg * glGenBuffers(&b, 100), because objects 1-50 and 101-200 are allocated at
7301e04c3fSmrg * the end of that sequence, instead of 1-150.  So far it doesn't appear to be
7401e04c3fSmrg * a problem.
7501e04c3fSmrg */
7601e04c3fSmrgstatic inline bool
7701e04c3fSmrguint_key_compare(const void *a, const void *b)
7801e04c3fSmrg{
7901e04c3fSmrg   return a == b;
8001e04c3fSmrg}
8101e04c3fSmrg
8201e04c3fSmrgstatic inline uint32_t
8301e04c3fSmrguint_hash(GLuint id)
8401e04c3fSmrg{
8501e04c3fSmrg   return id;
8601e04c3fSmrg}
8701e04c3fSmrg
8801e04c3fSmrgstatic inline uint32_t
8901e04c3fSmrguint_key_hash(const void *key)
9001e04c3fSmrg{
9101e04c3fSmrg   return uint_hash((uintptr_t)key);
9201e04c3fSmrg}
9301e04c3fSmrg
9401e04c3fSmrgstatic inline void *
9501e04c3fSmrguint_key(GLuint id)
9601e04c3fSmrg{
9701e04c3fSmrg   return (void *)(uintptr_t) id;
9801e04c3fSmrg}
9901e04c3fSmrg/** @} */
10001e04c3fSmrg
10101e04c3fSmrg/**
10201e04c3fSmrg * The hash table data structure.
10301e04c3fSmrg */
10401e04c3fSmrgstruct _mesa_HashTable {
10501e04c3fSmrg   struct hash_table *ht;
10601e04c3fSmrg   GLuint MaxKey;                        /**< highest key inserted so far */
1077ec681f3Smrg   simple_mtx_t Mutex;                   /**< mutual exclusion lock */
1087ec681f3Smrg   /* Used when name reuse is enabled */
1097ec681f3Smrg   struct util_idalloc* id_alloc;
1107ec681f3Smrg
11101e04c3fSmrg   /** Value that would be in the table for DELETED_KEY_VALUE. */
11201e04c3fSmrg   void *deleted_key_data;
1137ec681f3Smrg   #ifndef NDEBUG
1147ec681f3Smrg   GLboolean InDeleteAll;                /**< Debug check */
1157ec681f3Smrg   #endif
11601e04c3fSmrg};
1177117f1b4Smrg
1187117f1b4Smrgextern struct _mesa_HashTable *_mesa_NewHashTable(void);
1197117f1b4Smrg
1207117f1b4Smrgextern void _mesa_DeleteHashTable(struct _mesa_HashTable *table);
1217117f1b4Smrg
1224a49301eSmrgextern void *_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key);
1237117f1b4Smrg
1247ec681f3Smrgextern void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data,
1257ec681f3Smrg                             GLboolean isGenName);
1267117f1b4Smrg
1277117f1b4Smrgextern void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key);
1287117f1b4Smrg
12901e04c3fSmrg/**
13001e04c3fSmrg * Lock the hash table mutex.
13101e04c3fSmrg *
13201e04c3fSmrg * This function should be used when multiple objects need
13301e04c3fSmrg * to be looked up in the hash table, to avoid having to lock
13401e04c3fSmrg * and unlock the mutex each time.
13501e04c3fSmrg *
13601e04c3fSmrg * \param table the hash table.
13701e04c3fSmrg */
13801e04c3fSmrgstatic inline void
13901e04c3fSmrg_mesa_HashLockMutex(struct _mesa_HashTable *table)
14001e04c3fSmrg{
14101e04c3fSmrg   assert(table);
1427ec681f3Smrg   simple_mtx_lock(&table->Mutex);
14301e04c3fSmrg}
14401e04c3fSmrg
145af69d88dSmrg
14601e04c3fSmrg/**
14701e04c3fSmrg * Unlock the hash table mutex.
14801e04c3fSmrg *
14901e04c3fSmrg * \param table the hash table.
15001e04c3fSmrg */
15101e04c3fSmrgstatic inline void
15201e04c3fSmrg_mesa_HashUnlockMutex(struct _mesa_HashTable *table)
15301e04c3fSmrg{
15401e04c3fSmrg   assert(table);
1557ec681f3Smrg   simple_mtx_unlock(&table->Mutex);
15601e04c3fSmrg}
157af69d88dSmrg
158af69d88dSmrgextern void *_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key);
159af69d88dSmrg
160af69d88dSmrgextern void _mesa_HashInsertLocked(struct _mesa_HashTable *table,
1617ec681f3Smrg                                   GLuint key, void *data, GLboolean isGenName);
162af69d88dSmrg
16301e04c3fSmrgextern void _mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key);
16401e04c3fSmrg
1657117f1b4Smrgextern void
1667117f1b4Smrg_mesa_HashDeleteAll(struct _mesa_HashTable *table,
1677ec681f3Smrg                    void (*callback)(void *data, void *userData),
1687117f1b4Smrg                    void *userData);
1697117f1b4Smrg
1707117f1b4Smrgextern void
1717117f1b4Smrg_mesa_HashWalk(const struct _mesa_HashTable *table,
1727ec681f3Smrg               void (*callback)(void *data, void *userData),
1737117f1b4Smrg               void *userData);
1747117f1b4Smrg
17501e04c3fSmrgextern void
17601e04c3fSmrg_mesa_HashWalkLocked(const struct _mesa_HashTable *table,
1777ec681f3Smrg                     void (*callback)(void *data, void *userData),
17801e04c3fSmrg                     void *userData);
17901e04c3fSmrg
1807117f1b4Smrgextern void _mesa_HashPrint(const struct _mesa_HashTable *table);
1817117f1b4Smrg
1827117f1b4Smrgextern GLuint _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys);
1837117f1b4Smrg
1847ec681f3Smrgextern bool
1857ec681f3Smrg_mesa_HashFindFreeKeys(struct _mesa_HashTable *table, GLuint* keys, GLuint numKeys);
1867ec681f3Smrg
187af69d88dSmrgextern GLuint
188af69d88dSmrg_mesa_HashNumEntries(const struct _mesa_HashTable *table);
189af69d88dSmrg
1907117f1b4Smrgextern void _mesa_test_hash_functions(void);
1917117f1b4Smrg
1927ec681f3Smrgextern void _mesa_HashEnableNameReuse(struct _mesa_HashTable *table);
1937ec681f3Smrg
1947ec681f3Smrgstatic inline void
1957ec681f3Smrg_mesa_HashWalkMaybeLocked(const struct _mesa_HashTable *table,
1967ec681f3Smrg                            void (*callback)(void *data, void *userData),
1977ec681f3Smrg                            void *userData, bool locked)
1987ec681f3Smrg{
1997ec681f3Smrg   if (locked)
2007ec681f3Smrg      _mesa_HashWalkLocked(table, callback, userData);
2017ec681f3Smrg   else
2027ec681f3Smrg      _mesa_HashWalk(table, callback, userData);
2037ec681f3Smrg}
2047ec681f3Smrg
2057ec681f3Smrgstatic inline struct gl_buffer_object *
2067ec681f3Smrg_mesa_HashLookupMaybeLocked(struct _mesa_HashTable *table, GLuint key,
2077ec681f3Smrg                            bool locked)
2087ec681f3Smrg{
2097ec681f3Smrg   if (locked)
2107ec681f3Smrg      return _mesa_HashLookupLocked(table, key);
2117ec681f3Smrg   else
2127ec681f3Smrg      return _mesa_HashLookup(table, key);
2137ec681f3Smrg}
2147ec681f3Smrg
2157ec681f3Smrgstatic inline void
2167ec681f3Smrg_mesa_HashInsertMaybeLocked(struct _mesa_HashTable *table,
2177ec681f3Smrg                            GLuint key, void *data, GLboolean isGenName,
2187ec681f3Smrg                            bool locked)
2197ec681f3Smrg{
2207ec681f3Smrg   if (locked)
2217ec681f3Smrg      _mesa_HashInsertLocked(table, key, data, isGenName);
2227ec681f3Smrg   else
2237ec681f3Smrg      _mesa_HashInsert(table, key, data, isGenName);
2247ec681f3Smrg}
2257ec681f3Smrg
2267ec681f3Smrgstatic inline void
2277ec681f3Smrg_mesa_HashLockMaybeLocked(struct _mesa_HashTable *table, bool locked)
2287ec681f3Smrg{
2297ec681f3Smrg   if (!locked)
2307ec681f3Smrg      _mesa_HashLockMutex(table);
2317ec681f3Smrg}
2327ec681f3Smrg
2337ec681f3Smrgstatic inline void
2347ec681f3Smrg_mesa_HashUnlockMaybeLocked(struct _mesa_HashTable *table, bool locked)
2357ec681f3Smrg{
2367ec681f3Smrg   if (!locked)
2377ec681f3Smrg      _mesa_HashUnlockMutex(table);
2387ec681f3Smrg}
2397117f1b4Smrg
2407117f1b4Smrg#endif
241