Optimize swapchain OOM tests am: 1614827a71 am: 2cfe132119 am: 00ab17bd23 am: c9b7dae8a8
[platform/upstream/VK-GL-CTS.git] / framework / delibs / depool / dePoolHash.h
1 #ifndef _DEPOOLHASH_H
2 #define _DEPOOLHASH_H
3 /*-------------------------------------------------------------------------
4  * drawElements Memory Pool Library
5  * --------------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Memory pool hash class.
24  *//*--------------------------------------------------------------------*/
25
26 #include "deDefs.h"
27 #include "deMemPool.h"
28 #include "dePoolArray.h"
29 #include "deInt32.h"
30
31 #include <string.h> /* memset() */
32
33 enum
34 {
35         DE_HASH_ELEMENTS_PER_SLOT       = 4
36 };
37
38 DE_BEGIN_EXTERN_C
39
40 void    dePoolHash_selfTest             (void);
41
42 DE_END_EXTERN_C
43
44 /*--------------------------------------------------------------------*//*!
45  * \brief Declare a template pool hash class interface.
46  * \param TYPENAME      Type name of the declared hash.
47  * \param KEYTYPE       Type of the key.
48  * \param VALUETYPE     Type of the value.
49  *
50  * This macro declares the interface for a hash. For the implementation of
51  * the hash, see DE_IMPLEMENT_POOL_HASH. Usually this macro is put into the
52  * header file and the implementation macro is put in some .c file.
53  *
54  * \todo [petri] Detailed description.
55  *
56  * The functions for operating the hash are:
57  * \todo [petri] Figure out how to comment these in Doxygen-style.
58  *
59  * \code
60  * Hash*    Hash_create            (deMemPool* pool);
61  * int      Hash_getNumElements    (const Hash* hash);
62  * Value*   Hash_find              (Hash* hash, Key key);
63  * deBool   Hash_insert            (Hash* hash, Key key, Value value);
64  * void     Hash_delete            (Hash* hash, Key key);
65  * \endcode
66 *//*--------------------------------------------------------------------*/
67 #define DE_DECLARE_POOL_HASH(TYPENAME, KEYTYPE, VALUETYPE)              \
68 \
69 typedef struct TYPENAME##Slot_s TYPENAME##Slot;    \
70 \
71 struct TYPENAME##Slot_s \
72 {    \
73         int                             numUsed; \
74         TYPENAME##Slot* nextSlot; \
75         KEYTYPE                 keys[DE_HASH_ELEMENTS_PER_SLOT]; \
76         VALUETYPE               values[DE_HASH_ELEMENTS_PER_SLOT]; \
77 }; \
78 \
79 typedef struct TYPENAME##_s    \
80 {    \
81         deMemPool*                      pool;                           \
82         int                                     numElements;            \
83 \
84         int                                     slotTableSize;          \
85         TYPENAME##Slot**        slotTable;                      \
86         TYPENAME##Slot*         slotFreeList;           \
87 } TYPENAME; /* NOLINT(TYPENAME) */                      \
88 \
89 typedef struct TYPENAME##Iter_s \
90 {       \
91         const TYPENAME*                 hash;                   \
92         int                                             curSlotIndex;   \
93         const TYPENAME##Slot*   curSlot;                \
94         int                                             curElemIndex;   \
95 } TYPENAME##Iter;       \
96 \
97 TYPENAME*       TYPENAME##_create       (deMemPool* pool);                                                                                      \
98 void            TYPENAME##_reset        (DE_PTR_TYPE(TYPENAME) hash);                                                           \
99 deBool          TYPENAME##_reserve      (DE_PTR_TYPE(TYPENAME) hash, int capacity);                                     \
100 VALUETYPE*      TYPENAME##_find         (const TYPENAME* hash, KEYTYPE key);                                            \
101 deBool          TYPENAME##_insert       (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key, VALUETYPE value);     \
102 void            TYPENAME##_delete       (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key);                                      \
103 \
104 DE_INLINE int           TYPENAME##_getNumElements       (const TYPENAME* hash)                                                  DE_UNUSED_FUNCTION;     \
105 DE_INLINE void          TYPENAME##Iter_init                     (const TYPENAME* hash, TYPENAME##Iter* iter)    DE_UNUSED_FUNCTION;     \
106 DE_INLINE deBool        TYPENAME##Iter_hasItem          (const TYPENAME##Iter* iter)                                    DE_UNUSED_FUNCTION;     \
107 DE_INLINE void          TYPENAME##Iter_next                     (TYPENAME##Iter* iter)                                                  DE_UNUSED_FUNCTION;     \
108 DE_INLINE KEYTYPE       TYPENAME##Iter_getKey           (const TYPENAME##Iter* iter)                                    DE_UNUSED_FUNCTION;     \
109 DE_INLINE VALUETYPE     TYPENAME##Iter_getValue         (const TYPENAME##Iter* iter)                                    DE_UNUSED_FUNCTION;     \
110 \
111 DE_INLINE int TYPENAME##_getNumElements (const TYPENAME* hash)    \
112 {    \
113         return hash->numElements;    \
114 }    \
115 \
116 DE_INLINE void TYPENAME##Iter_init (const TYPENAME* hash, TYPENAME##Iter* iter)    \
117 {       \
118         iter->hash                      = hash;         \
119         iter->curSlotIndex      = 0;            \
120         iter->curSlot           = DE_NULL;      \
121         iter->curElemIndex      = 0;            \
122         if (TYPENAME##_getNumElements(hash) > 0)                \
123         {                                                                                               \
124                 int slotTableSize       = hash->slotTableSize;  \
125                 int slotNdx                     = 0;                                    \
126                 while (slotNdx < slotTableSize)                         \
127                 {                                                                                       \
128                         if (hash->slotTable[slotNdx])                   \
129                                 break;                                                          \
130                         slotNdx++;                                                              \
131                 }                                                                                       \
132                 DE_ASSERT(slotNdx < slotTableSize);                     \
133                 iter->curSlotIndex = slotNdx;                           \
134                 iter->curSlot = hash->slotTable[slotNdx];       \
135                 DE_ASSERT(iter->curSlot);                                       \
136         }       \
137 }       \
138 \
139 DE_INLINE deBool TYPENAME##Iter_hasItem (const TYPENAME##Iter* iter)    \
140 {       \
141         return (iter->curSlot != DE_NULL); \
142 }       \
143 \
144 DE_INLINE void TYPENAME##Iter_next (TYPENAME##Iter* iter)    \
145 {       \
146         DE_ASSERT(TYPENAME##Iter_hasItem(iter));        \
147         if (++iter->curElemIndex == iter->curSlot->numUsed)     \
148         {                                                                                                       \
149                 iter->curElemIndex = 0;                                                 \
150                 if (iter->curSlot->nextSlot)                                    \
151                 {                                                                                               \
152                         iter->curSlot = iter->curSlot->nextSlot;        \
153                 }                                                                                               \
154                 else                                                                                    \
155                 {                                                                                               \
156                         const TYPENAME* hash                    = iter->hash;                   \
157                         int                             curSlotIndex    = iter->curSlotIndex;   \
158                         int                             slotTableSize   = hash->slotTableSize;  \
159                         while (++curSlotIndex < slotTableSize)          \
160                         {                                                                                       \
161                                 if (hash->slotTable[curSlotIndex])              \
162                                         break;                                                          \
163                         }                                                                                       \
164                         iter->curSlotIndex = curSlotIndex;                      \
165                         if (curSlotIndex < slotTableSize)                                       \
166                                 iter->curSlot = hash->slotTable[curSlotIndex];  \
167                         else                                                                                            \
168                                 iter->curSlot = DE_NULL;                                                \
169                 }       \
170         }       \
171 }       \
172 \
173 DE_INLINE KEYTYPE TYPENAME##Iter_getKey (const TYPENAME##Iter* iter)    \
174 {       \
175         DE_ASSERT(TYPENAME##Iter_hasItem(iter));        \
176         return iter->curSlot->keys[iter->curElemIndex]; \
177 }       \
178 \
179 DE_INLINE VALUETYPE     TYPENAME##Iter_getValue (const TYPENAME##Iter* iter)    \
180 {       \
181         DE_ASSERT(TYPENAME##Iter_hasItem(iter));        \
182         return iter->curSlot->values[iter->curElemIndex];       \
183 }       \
184 \
185 struct TYPENAME##Dummy_s { int dummy; }
186
187 /*--------------------------------------------------------------------*//*!
188  * \brief Implement a template pool hash class.
189  * \param TYPENAME      Type name of the declared hash.
190  * \param KEYTYPE       Type of the key.
191  * \param VALUETYPE     Type of the value.
192  * \param HASHFUNC      Function used for hashing the key.
193  * \param CMPFUNC       Function used for exact matching of the keys.
194  *
195  * This macro has implements the hash declared with DE_DECLARE_POOL_HASH.
196  * Usually this macro should be used from a .c file, since the macro expands
197  * into multiple functions. The TYPENAME, KEYTYPE, and VALUETYPE parameters
198  * must match those of the declare macro.
199 *//*--------------------------------------------------------------------*/
200 #define DE_IMPLEMENT_POOL_HASH(TYPENAME, KEYTYPE, VALUETYPE, HASHFUNC, CMPFUNC)         \
201 \
202 TYPENAME* TYPENAME##_create (deMemPool* pool)    \
203 {   \
204         /* Alloc struct. */ \
205         DE_PTR_TYPE(TYPENAME) hash = DE_POOL_NEW(pool, TYPENAME); \
206         if (!hash) \
207                 return DE_NULL; \
208 \
209         memset(hash, 0, sizeof(TYPENAME)); \
210         hash->pool = pool; \
211 \
212         return hash; \
213 } \
214 \
215 void TYPENAME##_reset (DE_PTR_TYPE(TYPENAME) hash)    \
216 {   \
217         int slotNdx; \
218         for (slotNdx = 0; slotNdx < hash->slotTableSize; slotNdx++)     \
219         {       \
220                 TYPENAME##Slot* slot = hash->slotTable[slotNdx]; \
221                 while (slot) \
222                 { \
223                         TYPENAME##Slot* nextSlot = slot->nextSlot;      \
224                         slot->nextSlot = hash->slotFreeList;            \
225                         hash->slotFreeList = slot;      \
226                         slot->numUsed = 0;                      \
227                         slot = nextSlot;                        \
228                 }       \
229                 hash->slotTable[slotNdx] = DE_NULL; \
230         }       \
231         hash->numElements = 0; \
232 }       \
233 \
234 TYPENAME##Slot* TYPENAME##_allocSlot (DE_PTR_TYPE(TYPENAME) hash)    \
235 {   \
236         TYPENAME##Slot* slot; \
237         if (hash->slotFreeList) \
238         { \
239                 slot = hash->slotFreeList; \
240                 hash->slotFreeList = hash->slotFreeList->nextSlot; \
241         } \
242         else \
243                 slot = (TYPENAME##Slot*)deMemPool_alloc(hash->pool, sizeof(TYPENAME##Slot) * DE_HASH_ELEMENTS_PER_SLOT); \
244 \
245         if (slot) \
246         { \
247                 slot->nextSlot = DE_NULL; \
248                 slot->numUsed = 0; \
249         } \
250 \
251         return slot; \
252 } \
253 \
254 deBool TYPENAME##_rehash (DE_PTR_TYPE(TYPENAME) hash, int newSlotTableSize)    \
255 {    \
256         DE_ASSERT(deIsPowerOfTwo32(newSlotTableSize) && newSlotTableSize > 0); \
257         if (newSlotTableSize > hash->slotTableSize)    \
258         { \
259                 TYPENAME##Slot**        oldSlotTable = hash->slotTable; \
260                 TYPENAME##Slot**        newSlotTable = (TYPENAME##Slot**)deMemPool_alloc(hash->pool, sizeof(TYPENAME##Slot*) * (size_t)newSlotTableSize); \
261                 int                                     oldSlotTableSize = hash->slotTableSize; \
262                 int                                     slotNdx; \
263 \
264                 if (!newSlotTable) \
265                         return DE_FALSE; \
266 \
267                 for (slotNdx = 0; slotNdx < oldSlotTableSize; slotNdx++) \
268                         newSlotTable[slotNdx] = oldSlotTable[slotNdx]; \
269 \
270                 for (slotNdx = oldSlotTableSize; slotNdx < newSlotTableSize; slotNdx++) \
271                         newSlotTable[slotNdx] = DE_NULL; \
272 \
273                 hash->slotTableSize             = newSlotTableSize; \
274                 hash->slotTable                 = newSlotTable; \
275 \
276                 for (slotNdx = 0; slotNdx < oldSlotTableSize; slotNdx++) \
277                 { \
278                         TYPENAME##Slot* slot = oldSlotTable[slotNdx]; \
279                         newSlotTable[slotNdx] = DE_NULL; \
280                         while (slot) \
281                         { \
282                                 int elemNdx; \
283                                 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
284                                 { \
285                                         hash->numElements--; \
286                                         if (!TYPENAME##_insert(hash, slot->keys[elemNdx], slot->values[elemNdx])) \
287                                                 return DE_FALSE; \
288                                 } \
289                                 slot = slot->nextSlot; \
290                         } \
291                 } \
292         } \
293 \
294         return DE_TRUE;    \
295 }    \
296 \
297 VALUETYPE* TYPENAME##_find (const TYPENAME* hash, KEYTYPE key)    \
298 {    \
299         if (hash->numElements > 0) \
300         {       \
301                 int                             slotNdx = (int)(HASHFUNC(key) & (deUint32)(hash->slotTableSize - 1)); \
302                 TYPENAME##Slot* slot    = hash->slotTable[slotNdx]; \
303                 DE_ASSERT(deInBounds32(slotNdx, 0, hash->slotTableSize)); \
304         \
305                 while (slot) \
306                 { \
307                         int elemNdx; \
308                         for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
309                         { \
310                                 if (CMPFUNC(slot->keys[elemNdx], key)) \
311                                         return &slot->values[elemNdx]; \
312                         } \
313                         slot = slot->nextSlot; \
314                 } \
315         } \
316 \
317         return DE_NULL; \
318 }    \
319 \
320 deBool TYPENAME##_insert (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key, VALUETYPE value)    \
321 {    \
322         int                             slotNdx; \
323         TYPENAME##Slot* slot; \
324 \
325         DE_ASSERT(!TYPENAME##_find(hash, key)); \
326 \
327         if ((hash->numElements + 1) >= hash->slotTableSize * DE_HASH_ELEMENTS_PER_SLOT) \
328                 if (!TYPENAME##_rehash(hash, deMax32(4, 2*hash->slotTableSize))) \
329                         return DE_FALSE; \
330 \
331         slotNdx = (int)(HASHFUNC(key) & (deUint32)(hash->slotTableSize - 1)); \
332         DE_ASSERT(slotNdx >= 0 && slotNdx < hash->slotTableSize); \
333         slot    = hash->slotTable[slotNdx]; \
334 \
335         if (!slot) \
336         { \
337                 slot = TYPENAME##_allocSlot(hash); \
338                 if (!slot) return DE_FALSE; \
339                 hash->slotTable[slotNdx] = slot; \
340         } \
341 \
342         for (;;) \
343         { \
344                 if (slot->numUsed == DE_HASH_ELEMENTS_PER_SLOT) \
345                 { \
346                         if (slot->nextSlot) \
347                                 slot = slot->nextSlot; \
348                         else \
349                         { \
350                                 TYPENAME##Slot* nextSlot = TYPENAME##_allocSlot(hash); \
351                                 if (!nextSlot) return DE_FALSE; \
352                                 slot->nextSlot = nextSlot; \
353                                 slot = nextSlot; \
354                         } \
355                 } \
356                 else \
357                 { \
358                         slot->keys[slot->numUsed]       = key; \
359                         slot->values[slot->numUsed]     = value; \
360                         slot->numUsed++; \
361                         hash->numElements++; \
362                         return DE_TRUE; \
363                 } \
364         } \
365 } \
366 \
367 void TYPENAME##_delete (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key)    \
368 {    \
369         int                             slotNdx; \
370         TYPENAME##Slot* slot; \
371         TYPENAME##Slot* prevSlot = DE_NULL; \
372 \
373         DE_ASSERT(hash->numElements > 0); \
374         slotNdx = (int)(HASHFUNC(key) & (deUint32)(hash->slotTableSize - 1)); \
375         DE_ASSERT(slotNdx >= 0 && slotNdx < hash->slotTableSize); \
376         slot    = hash->slotTable[slotNdx]; \
377         DE_ASSERT(slot); \
378 \
379         for (;;) \
380         { \
381                 int elemNdx; \
382                 DE_ASSERT(slot->numUsed > 0); \
383                 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
384                 { \
385                         if (CMPFUNC(slot->keys[elemNdx], key)) \
386                         { \
387                                 TYPENAME##Slot* lastSlot = slot; \
388                                 while (lastSlot->nextSlot) \
389                                 { \
390                                         prevSlot = lastSlot; \
391                                         lastSlot = lastSlot->nextSlot; \
392                                 } \
393 \
394                                 slot->keys[elemNdx]             = lastSlot->keys[lastSlot->numUsed-1]; \
395                                 slot->values[elemNdx]   = lastSlot->values[lastSlot->numUsed-1]; \
396                                 lastSlot->numUsed--; \
397 \
398                                 if (lastSlot->numUsed == 0) \
399                                 { \
400                                         if (prevSlot) \
401                                                 prevSlot->nextSlot = DE_NULL; \
402                                         else \
403                                                 hash->slotTable[slotNdx] = DE_NULL; \
404 \
405                                         lastSlot->nextSlot = hash->slotFreeList; \
406                                         hash->slotFreeList = lastSlot; \
407                                 } \
408 \
409                                 hash->numElements--; \
410                                 return; \
411                         } \
412                 } \
413 \
414                 prevSlot = slot; \
415                 slot = slot->nextSlot; \
416                 DE_ASSERT(slot); \
417         } \
418 }    \
419 struct TYPENAME##Dummy2_s { int dummy; }
420
421 /* Copy-to-array templates. */
422
423 #define DE_DECLARE_POOL_HASH_TO_ARRAY(HASHTYPENAME, KEYARRAYTYPENAME, VALUEARRAYTYPENAME)               \
424         deBool HASHTYPENAME##_copyToArray(const HASHTYPENAME* set, DE_PTR_TYPE(KEYARRAYTYPENAME) keyArray, DE_PTR_TYPE(VALUEARRAYTYPENAME) valueArray); \
425         struct HASHTYPENAME##_##KEYARRAYTYPENAME##_##VALUEARRAYTYPENAME##_declare_dummy { int dummy; }
426
427 #define DE_IMPLEMENT_POOL_HASH_TO_ARRAY(HASHTYPENAME, KEYARRAYTYPENAME, VALUEARRAYTYPENAME)             \
428 deBool HASHTYPENAME##_copyToArray(const HASHTYPENAME* hash, DE_PTR_TYPE(KEYARRAYTYPENAME) keyArray, DE_PTR_TYPE(VALUEARRAYTYPENAME) valueArray) \
429 {       \
430         int numElements = hash->numElements;    \
431         int arrayNdx    = 0;    \
432         int slotNdx;    \
433         \
434         if ((keyArray && !KEYARRAYTYPENAME##_setSize(keyArray, numElements)) ||                 \
435                 (valueArray && !VALUEARRAYTYPENAME##_setSize(valueArray, numElements)))         \
436                 return DE_FALSE;        \
437         \
438         for (slotNdx = 0; slotNdx < hash->slotTableSize; slotNdx++) \
439         { \
440                 const HASHTYPENAME##Slot* slot = hash->slotTable[slotNdx]; \
441                 while (slot) \
442                 { \
443                         int elemNdx; \
444                         for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
445                         {       \
446                                 if (keyArray)   \
447                                         KEYARRAYTYPENAME##_set(keyArray, arrayNdx, slot->keys[elemNdx]); \
448                                 if (valueArray) \
449                                         VALUEARRAYTYPENAME##_set(valueArray, arrayNdx, slot->values[elemNdx]);  \
450                                 arrayNdx++;     \
451                         } \
452                         slot = slot->nextSlot; \
453                 } \
454         }       \
455         DE_ASSERT(arrayNdx == numElements);     \
456         return DE_TRUE; \
457 }       \
458 struct HASHTYPENAME##_##KEYARRAYTYPENAME##_##VALUEARRAYTYPENAME##_implement_dummy { int dummy; }
459
460 #endif /* _DEPOOLHASH_H */