1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful but, except
10 * as otherwise stated in writing, without any warranty; without even the
11 * implied warranty of merchantability or fitness for a particular purpose.
12 * See the GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #include "pvr_debug.h"
30 #include "servicesint.h"
34 #define PRIVATE_MAX(a, b) ((a) > (b) ? (a) : (b))
36 #define KEY_TO_INDEX(pHash, key, uSize) \
37 ((pHash)->pfnHashFunc((pHash)->uKeySize, key, uSize) % uSize)
39 #define KEY_COMPARE(pHash, pKey1, pKey2) \
40 ((pHash)->pfnKeyComp((pHash)->uKeySize, pKey1, pKey2))
50 struct BUCKET **ppBucketTable;
55 u32 (*pfnHashFunc)(size_t uKeySize, void *pkey, u32 uHashTabLen);
56 IMG_BOOL (*pfnKeyComp)(size_t uKeySize, void *pKey1, void *pkey2);
59 u32 HASH_Func_Default(size_t uKeySize, void *pKey, u32 uHashTabLen)
61 u32 *p = (u32 *) pKey;
62 u32 uKeyLen = uKeySize / sizeof(u32);
66 PVR_UNREFERENCED_PARAMETER(uHashTabLen);
68 PVR_ASSERT((uKeySize % sizeof(u32)) == 0);
70 for (ui = 0; ui < uKeyLen; ui++) {
71 u32 uHashPart = (u32) *p++;
73 uHashPart += (uHashPart << 12);
74 uHashPart ^= (uHashPart >> 22);
75 uHashPart += (uHashPart << 4);
76 uHashPart ^= (uHashPart >> 9);
77 uHashPart += (uHashPart << 10);
78 uHashPart ^= (uHashPart >> 2);
79 uHashPart += (uHashPart << 7);
80 uHashPart ^= (uHashPart >> 12);
82 uHashKey += uHashPart;
88 IMG_BOOL HASH_Key_Comp_Default(size_t uKeySize, void *pKey1, void *pKey2)
90 u32 *p1 = (u32 *) pKey1;
91 u32 *p2 = (u32 *) pKey2;
92 u32 uKeyLen = uKeySize / sizeof(u32);
95 PVR_ASSERT((uKeySize % sizeof(u32)) == 0);
97 for (ui = 0; ui < uKeyLen; ui++)
104 static enum PVRSRV_ERROR _ChainInsert(struct HASH_TABLE *pHash,
105 struct BUCKET *pBucket,
106 struct BUCKET **ppBucketTable, u32 uSize)
110 PVR_ASSERT(pBucket != NULL);
111 PVR_ASSERT(ppBucketTable != NULL);
112 PVR_ASSERT(uSize != 0);
114 if ((pBucket == NULL) || (ppBucketTable == NULL) || (uSize == 0)) {
115 PVR_DPF(PVR_DBG_ERROR, "_ChainInsert: invalid parameter");
116 return PVRSRV_ERROR_INVALID_PARAMS;
119 uIndex = KEY_TO_INDEX(pHash, pBucket->k, uSize);
120 pBucket->pNext = ppBucketTable[uIndex];
121 ppBucketTable[uIndex] = pBucket;
126 static enum PVRSRV_ERROR _Rehash(struct HASH_TABLE *pHash,
127 struct BUCKET **ppOldTable, u32 uOldSize,
128 struct BUCKET **ppNewTable, u32 uNewSize)
131 for (uIndex = 0; uIndex < uOldSize; uIndex++) {
132 struct BUCKET *pBucket;
133 pBucket = ppOldTable[uIndex];
134 while (pBucket != NULL) {
135 struct BUCKET *pNextBucket = pBucket->pNext;
136 if (_ChainInsert(pHash, pBucket, ppNewTable, uNewSize)
138 PVR_DPF(PVR_DBG_ERROR,
139 "_Rehash: call to _ChainInsert failed");
140 return PVRSRV_ERROR_GENERIC;
142 pBucket = pNextBucket;
148 static IMG_BOOL _Resize(struct HASH_TABLE *pHash, u32 uNewSize)
150 if (uNewSize != pHash->uSize) {
151 struct BUCKET **ppNewTable;
154 PVR_DPF(PVR_DBG_MESSAGE,
155 "HASH_Resize: oldsize=0x%x newsize=0x%x count=0x%x",
156 pHash->uSize, uNewSize, pHash->uCount);
158 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
159 sizeof(struct BUCKET *) * uNewSize,
160 (void **) &ppNewTable, NULL) != PVRSRV_OK)
163 for (uIndex = 0; uIndex < uNewSize; uIndex++)
164 ppNewTable[uIndex] = NULL;
166 if (_Rehash(pHash, pHash->ppBucketTable, pHash->uSize,
167 ppNewTable, uNewSize) != PVRSRV_OK)
170 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
171 sizeof(struct BUCKET *) * pHash->uSize,
172 pHash->ppBucketTable, NULL);
173 pHash->ppBucketTable = ppNewTable;
174 pHash->uSize = uNewSize;
179 struct HASH_TABLE *HASH_Create_Extended(u32 uInitialLen, size_t uKeySize,
180 u32 (*pfnHashFunc)(size_t uKeySize, void *pkey,
182 IMG_BOOL (*pfnKeyComp)(size_t uKeySize,
186 struct HASH_TABLE *pHash;
189 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Create_Extended: InitialSize=0x%x",
192 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
193 sizeof(struct HASH_TABLE),
194 (void **) &pHash, NULL) != PVRSRV_OK)
198 pHash->uSize = uInitialLen;
199 pHash->uMinimumSize = uInitialLen;
200 pHash->uKeySize = uKeySize;
201 pHash->pfnHashFunc = pfnHashFunc;
202 pHash->pfnKeyComp = pfnKeyComp;
204 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
205 sizeof(struct BUCKET *) * pHash->uSize,
206 (void **) &pHash->ppBucketTable, NULL) != PVRSRV_OK) {
207 OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE),
212 for (uIndex = 0; uIndex < pHash->uSize; uIndex++)
213 pHash->ppBucketTable[uIndex] = NULL;
217 struct HASH_TABLE *HASH_Create(u32 uInitialLen)
219 return HASH_Create_Extended(uInitialLen, sizeof(u32),
220 &HASH_Func_Default, &HASH_Key_Comp_Default);
223 void HASH_Delete(struct HASH_TABLE *pHash)
226 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Delete");
228 PVR_ASSERT(pHash->uCount == 0);
229 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
230 sizeof(struct BUCKET *) * pHash->uSize,
231 pHash->ppBucketTable, NULL);
232 OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE),
237 IMG_BOOL HASH_Insert_Extended(struct HASH_TABLE *pHash, void *pKey, u32 v)
239 struct BUCKET *pBucket;
241 PVR_DPF(PVR_DBG_MESSAGE,
242 "HASH_Insert_Extended: Hash=%08X, pKey=%08X, v=0x%x", pHash,
245 PVR_ASSERT(pHash != NULL);
248 PVR_DPF(PVR_DBG_ERROR,
249 "HASH_Insert_Extended: invalid parameter");
253 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
254 sizeof(struct BUCKET) + pHash->uKeySize,
255 (void **) &pBucket, NULL) != PVRSRV_OK)
259 OSMemCopy(pBucket->k, pKey, pHash->uKeySize);
260 if (_ChainInsert(pHash, pBucket, pHash->ppBucketTable, pHash->uSize) !=
262 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
263 sizeof(struct BUCKET) + pHash->uKeySize,
270 if (pHash->uCount << 1 > pHash->uSize)
271 _Resize(pHash, pHash->uSize << 1);
276 IMG_BOOL HASH_Insert(struct HASH_TABLE *pHash, u32 k, u32 v)
278 PVR_DPF(PVR_DBG_MESSAGE,
279 "HASH_Insert: Hash=%08X, k=0x%x, v=0x%x", pHash, k, v);
281 return HASH_Insert_Extended(pHash, &k, v);
284 u32 HASH_Remove_Extended(struct HASH_TABLE *pHash, void *pKey)
286 struct BUCKET **ppBucket;
289 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, pKey=%08X", pHash,
292 PVR_ASSERT(pHash != NULL);
295 PVR_DPF(PVR_DBG_ERROR,
296 "FreeResourceByPtr: invalid parameter");
300 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
302 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL;
303 ppBucket = &((*ppBucket)->pNext))
304 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) {
305 struct BUCKET *pBucket = *ppBucket;
307 (*ppBucket) = pBucket->pNext;
309 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
310 sizeof(struct BUCKET) + pHash->uKeySize,
315 if (pHash->uSize > (pHash->uCount << 2) &&
316 pHash->uSize > pHash->uMinimumSize)
319 PRIVATE_MAX(pHash->uSize >> 1,
320 pHash->uMinimumSize));
322 PVR_DPF(PVR_DBG_MESSAGE,
323 "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x%x",
327 PVR_DPF(PVR_DBG_MESSAGE,
328 "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash,
333 u32 HASH_Remove(struct HASH_TABLE *pHash, u32 k)
335 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, k=0x%x", pHash, k);
337 return HASH_Remove_Extended(pHash, &k);
340 u32 HASH_Retrieve_Extended(struct HASH_TABLE *pHash, void *pKey)
342 struct BUCKET **ppBucket;
345 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, pKey=%08X", pHash,
348 PVR_ASSERT(pHash != NULL);
351 PVR_DPF(PVR_DBG_ERROR,
352 "HASH_Retrieve_Extended: invalid parameter");
356 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
358 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL;
359 ppBucket = &((*ppBucket)->pNext))
360 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) {
361 struct BUCKET *pBucket = *ppBucket;
364 PVR_DPF(PVR_DBG_MESSAGE,
365 "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x%x",
369 PVR_DPF(PVR_DBG_MESSAGE,
370 "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash, pKey);
374 u32 HASH_Retrieve(struct HASH_TABLE *pHash, u32 k)
376 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, k=0x%x", pHash, k);
377 return HASH_Retrieve_Extended(pHash, &k);