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 table_size = sizeof(struct BUCKET *) * uNewSize;
159 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, table_size,
160 (void **) &ppNewTable, NULL) != PVRSRV_OK)
163 memset(ppNewTable, 0, table_size);
165 if (_Rehash(pHash, pHash->ppBucketTable, pHash->uSize,
166 ppNewTable, uNewSize) != PVRSRV_OK) {
167 OSFreeMem(PVRSRV_PAGEABLE_SELECT, table_size,
172 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
173 sizeof(struct BUCKET *) * pHash->uSize,
174 pHash->ppBucketTable, NULL);
175 pHash->ppBucketTable = ppNewTable;
176 pHash->uSize = uNewSize;
181 struct HASH_TABLE *HASH_Create_Extended(u32 uInitialLen, size_t uKeySize,
182 u32 (*pfnHashFunc)(size_t uKeySize, void *pkey,
184 IMG_BOOL (*pfnKeyComp)(size_t uKeySize,
188 struct HASH_TABLE *pHash;
191 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Create_Extended: InitialSize=0x%x",
194 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
195 sizeof(struct HASH_TABLE),
196 (void **) &pHash, NULL) != PVRSRV_OK)
200 pHash->uSize = uInitialLen;
201 pHash->uMinimumSize = uInitialLen;
202 pHash->uKeySize = uKeySize;
203 pHash->pfnHashFunc = pfnHashFunc;
204 pHash->pfnKeyComp = pfnKeyComp;
206 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
207 sizeof(struct BUCKET *) * pHash->uSize,
208 (void **) &pHash->ppBucketTable, NULL) != PVRSRV_OK) {
209 OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE),
214 for (uIndex = 0; uIndex < pHash->uSize; uIndex++)
215 pHash->ppBucketTable[uIndex] = NULL;
219 struct HASH_TABLE *HASH_Create(u32 uInitialLen)
221 return HASH_Create_Extended(uInitialLen, sizeof(u32),
222 &HASH_Func_Default, &HASH_Key_Comp_Default);
225 void HASH_Delete(struct HASH_TABLE *pHash)
228 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Delete");
230 PVR_ASSERT(pHash->uCount == 0);
231 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
232 sizeof(struct BUCKET *) * pHash->uSize,
233 pHash->ppBucketTable, NULL);
234 OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE),
239 IMG_BOOL HASH_Insert_Extended(struct HASH_TABLE *pHash, void *pKey, u32 v)
241 struct BUCKET *pBucket;
243 PVR_DPF(PVR_DBG_MESSAGE,
244 "HASH_Insert_Extended: Hash=%08X, pKey=%08X, v=0x%x", pHash,
247 PVR_ASSERT(pHash != NULL);
250 PVR_DPF(PVR_DBG_ERROR,
251 "HASH_Insert_Extended: invalid parameter");
255 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
256 sizeof(struct BUCKET) + pHash->uKeySize,
257 (void **) &pBucket, NULL) != PVRSRV_OK)
261 OSMemCopy(pBucket->k, pKey, pHash->uKeySize);
262 if (_ChainInsert(pHash, pBucket, pHash->ppBucketTable, pHash->uSize) !=
264 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
265 sizeof(struct BUCKET) + pHash->uKeySize,
272 if (pHash->uCount << 1 > pHash->uSize)
273 _Resize(pHash, pHash->uSize << 1);
278 IMG_BOOL HASH_Insert(struct HASH_TABLE *pHash, u32 k, u32 v)
280 PVR_DPF(PVR_DBG_MESSAGE,
281 "HASH_Insert: Hash=%08X, k=0x%x, v=0x%x", pHash, k, v);
283 return HASH_Insert_Extended(pHash, &k, v);
286 u32 HASH_Remove_Extended(struct HASH_TABLE *pHash, void *pKey)
288 struct BUCKET **ppBucket;
291 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, pKey=%08X", pHash,
294 PVR_ASSERT(pHash != NULL);
297 PVR_DPF(PVR_DBG_ERROR,
298 "FreeResourceByPtr: invalid parameter");
302 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
304 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL;
305 ppBucket = &((*ppBucket)->pNext))
306 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) {
307 struct BUCKET *pBucket = *ppBucket;
309 (*ppBucket) = pBucket->pNext;
311 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
312 sizeof(struct BUCKET) + pHash->uKeySize,
317 if (pHash->uSize > (pHash->uCount << 2) &&
318 pHash->uSize > pHash->uMinimumSize)
321 PRIVATE_MAX(pHash->uSize >> 1,
322 pHash->uMinimumSize));
324 PVR_DPF(PVR_DBG_MESSAGE,
325 "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x%x",
329 PVR_DPF(PVR_DBG_MESSAGE,
330 "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash,
335 u32 HASH_Remove(struct HASH_TABLE *pHash, u32 k)
337 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, k=0x%x", pHash, k);
339 return HASH_Remove_Extended(pHash, &k);
342 u32 HASH_Retrieve_Extended(struct HASH_TABLE *pHash, void *pKey)
344 struct BUCKET **ppBucket;
347 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, pKey=%08X", pHash,
350 PVR_ASSERT(pHash != NULL);
353 PVR_DPF(PVR_DBG_ERROR,
354 "HASH_Retrieve_Extended: invalid parameter");
358 uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize);
360 for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL;
361 ppBucket = &((*ppBucket)->pNext))
362 if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) {
363 struct BUCKET *pBucket = *ppBucket;
366 PVR_DPF(PVR_DBG_MESSAGE,
367 "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x%x",
371 PVR_DPF(PVR_DBG_MESSAGE,
372 "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash, pKey);
376 u32 HASH_Retrieve(struct HASH_TABLE *pHash, u32 k)
378 PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, k=0x%x", pHash, k);
379 return HASH_Retrieve_Extended(pHash, &k);