3 /*-------------------------------------------------------------------------
4 * drawElements Memory Pool Library
5 * --------------------------------
7 * Copyright 2014 The Android Open Source Project
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * \brief Memory pool hash class.
24 *//*--------------------------------------------------------------------*/
27 #include "deMemPool.h"
28 #include "dePoolArray.h"
31 #include <string.h> /* memset() */
35 DE_HASH_ELEMENTS_PER_SLOT = 4
40 void dePoolHash_selfTest (void);
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.
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.
54 * \todo [petri] Detailed description.
56 * The functions for operating the hash are:
57 * \todo [petri] Figure out how to comment these in Doxygen-style.
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);
66 *//*--------------------------------------------------------------------*/
67 #define DE_DECLARE_POOL_HASH(TYPENAME, KEYTYPE, VALUETYPE) \
69 typedef struct TYPENAME##Slot_s TYPENAME##Slot; \
71 struct TYPENAME##Slot_s \
74 TYPENAME##Slot* nextSlot; \
75 KEYTYPE keys[DE_HASH_ELEMENTS_PER_SLOT]; \
76 VALUETYPE values[DE_HASH_ELEMENTS_PER_SLOT]; \
79 typedef struct TYPENAME##_s \
85 TYPENAME##Slot** slotTable; \
86 TYPENAME##Slot* slotFreeList; \
87 } TYPENAME; /* NOLINT(TYPENAME) */ \
89 typedef struct TYPENAME##Iter_s \
91 const TYPENAME* hash; \
93 const TYPENAME##Slot* curSlot; \
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); \
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; \
111 DE_INLINE int TYPENAME##_getNumElements (const TYPENAME* hash) \
113 return hash->numElements; \
116 DE_INLINE void TYPENAME##Iter_init (const TYPENAME* hash, TYPENAME##Iter* iter) \
119 iter->curSlotIndex = 0; \
120 iter->curSlot = DE_NULL; \
121 iter->curElemIndex = 0; \
122 if (TYPENAME##_getNumElements(hash) > 0) \
124 int slotTableSize = hash->slotTableSize; \
126 while (slotNdx < slotTableSize) \
128 if (hash->slotTable[slotNdx]) \
132 DE_ASSERT(slotNdx < slotTableSize); \
133 iter->curSlotIndex = slotNdx; \
134 iter->curSlot = hash->slotTable[slotNdx]; \
135 DE_ASSERT(iter->curSlot); \
139 DE_INLINE deBool TYPENAME##Iter_hasItem (const TYPENAME##Iter* iter) \
141 return (iter->curSlot != DE_NULL); \
144 DE_INLINE void TYPENAME##Iter_next (TYPENAME##Iter* iter) \
146 DE_ASSERT(TYPENAME##Iter_hasItem(iter)); \
147 if (++iter->curElemIndex == iter->curSlot->numUsed) \
149 iter->curElemIndex = 0; \
150 if (iter->curSlot->nextSlot) \
152 iter->curSlot = iter->curSlot->nextSlot; \
156 const TYPENAME* hash = iter->hash; \
157 int curSlotIndex = iter->curSlotIndex; \
158 int slotTableSize = hash->slotTableSize; \
159 while (++curSlotIndex < slotTableSize) \
161 if (hash->slotTable[curSlotIndex]) \
164 iter->curSlotIndex = curSlotIndex; \
165 if (curSlotIndex < slotTableSize) \
166 iter->curSlot = hash->slotTable[curSlotIndex]; \
168 iter->curSlot = DE_NULL; \
173 DE_INLINE KEYTYPE TYPENAME##Iter_getKey (const TYPENAME##Iter* iter) \
175 DE_ASSERT(TYPENAME##Iter_hasItem(iter)); \
176 return iter->curSlot->keys[iter->curElemIndex]; \
179 DE_INLINE VALUETYPE TYPENAME##Iter_getValue (const TYPENAME##Iter* iter) \
181 DE_ASSERT(TYPENAME##Iter_hasItem(iter)); \
182 return iter->curSlot->values[iter->curElemIndex]; \
185 struct TYPENAME##Dummy_s { int dummy; }
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.
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) \
202 TYPENAME* TYPENAME##_create (deMemPool* pool) \
204 /* Alloc struct. */ \
205 DE_PTR_TYPE(TYPENAME) hash = DE_POOL_NEW(pool, TYPENAME); \
209 memset(hash, 0, sizeof(TYPENAME)); \
215 void TYPENAME##_reset (DE_PTR_TYPE(TYPENAME) hash) \
218 for (slotNdx = 0; slotNdx < hash->slotTableSize; slotNdx++) \
220 TYPENAME##Slot* slot = hash->slotTable[slotNdx]; \
223 TYPENAME##Slot* nextSlot = slot->nextSlot; \
224 slot->nextSlot = hash->slotFreeList; \
225 hash->slotFreeList = slot; \
229 hash->slotTable[slotNdx] = DE_NULL; \
231 hash->numElements = 0; \
234 TYPENAME##Slot* TYPENAME##_allocSlot (DE_PTR_TYPE(TYPENAME) hash) \
236 TYPENAME##Slot* slot; \
237 if (hash->slotFreeList) \
239 slot = hash->slotFreeList; \
240 hash->slotFreeList = hash->slotFreeList->nextSlot; \
243 slot = (TYPENAME##Slot*)deMemPool_alloc(hash->pool, sizeof(TYPENAME##Slot) * DE_HASH_ELEMENTS_PER_SLOT); \
247 slot->nextSlot = DE_NULL; \
254 deBool TYPENAME##_rehash (DE_PTR_TYPE(TYPENAME) hash, int newSlotTableSize) \
256 DE_ASSERT(deIsPowerOfTwo32(newSlotTableSize) && newSlotTableSize > 0); \
257 if (newSlotTableSize > hash->slotTableSize) \
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; \
267 for (slotNdx = 0; slotNdx < oldSlotTableSize; slotNdx++) \
268 newSlotTable[slotNdx] = oldSlotTable[slotNdx]; \
270 for (slotNdx = oldSlotTableSize; slotNdx < newSlotTableSize; slotNdx++) \
271 newSlotTable[slotNdx] = DE_NULL; \
273 hash->slotTableSize = newSlotTableSize; \
274 hash->slotTable = newSlotTable; \
276 for (slotNdx = 0; slotNdx < oldSlotTableSize; slotNdx++) \
278 TYPENAME##Slot* slot = oldSlotTable[slotNdx]; \
279 newSlotTable[slotNdx] = DE_NULL; \
283 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
285 hash->numElements--; \
286 if (!TYPENAME##_insert(hash, slot->keys[elemNdx], slot->values[elemNdx])) \
289 slot = slot->nextSlot; \
297 VALUETYPE* TYPENAME##_find (const TYPENAME* hash, KEYTYPE key) \
299 if (hash->numElements > 0) \
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)); \
308 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
310 if (CMPFUNC(slot->keys[elemNdx], key)) \
311 return &slot->values[elemNdx]; \
313 slot = slot->nextSlot; \
320 deBool TYPENAME##_insert (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key, VALUETYPE value) \
323 TYPENAME##Slot* slot; \
325 DE_ASSERT(!TYPENAME##_find(hash, key)); \
327 if ((hash->numElements + 1) >= hash->slotTableSize * DE_HASH_ELEMENTS_PER_SLOT) \
328 if (!TYPENAME##_rehash(hash, deMax32(4, 2*hash->slotTableSize))) \
331 slotNdx = (int)(HASHFUNC(key) & (deUint32)(hash->slotTableSize - 1)); \
332 DE_ASSERT(slotNdx >= 0 && slotNdx < hash->slotTableSize); \
333 slot = hash->slotTable[slotNdx]; \
337 slot = TYPENAME##_allocSlot(hash); \
338 if (!slot) return DE_FALSE; \
339 hash->slotTable[slotNdx] = slot; \
344 if (slot->numUsed == DE_HASH_ELEMENTS_PER_SLOT) \
346 if (slot->nextSlot) \
347 slot = slot->nextSlot; \
350 TYPENAME##Slot* nextSlot = TYPENAME##_allocSlot(hash); \
351 if (!nextSlot) return DE_FALSE; \
352 slot->nextSlot = nextSlot; \
358 slot->keys[slot->numUsed] = key; \
359 slot->values[slot->numUsed] = value; \
361 hash->numElements++; \
367 void TYPENAME##_delete (DE_PTR_TYPE(TYPENAME) hash, KEYTYPE key) \
370 TYPENAME##Slot* slot; \
371 TYPENAME##Slot* prevSlot = DE_NULL; \
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]; \
382 DE_ASSERT(slot->numUsed > 0); \
383 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
385 if (CMPFUNC(slot->keys[elemNdx], key)) \
387 TYPENAME##Slot* lastSlot = slot; \
388 while (lastSlot->nextSlot) \
390 prevSlot = lastSlot; \
391 lastSlot = lastSlot->nextSlot; \
394 slot->keys[elemNdx] = lastSlot->keys[lastSlot->numUsed-1]; \
395 slot->values[elemNdx] = lastSlot->values[lastSlot->numUsed-1]; \
396 lastSlot->numUsed--; \
398 if (lastSlot->numUsed == 0) \
401 prevSlot->nextSlot = DE_NULL; \
403 hash->slotTable[slotNdx] = DE_NULL; \
405 lastSlot->nextSlot = hash->slotFreeList; \
406 hash->slotFreeList = lastSlot; \
409 hash->numElements--; \
415 slot = slot->nextSlot; \
419 struct TYPENAME##Dummy2_s { int dummy; }
421 /* Copy-to-array templates. */
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; }
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) \
430 int numElements = hash->numElements; \
434 if ((keyArray && !KEYARRAYTYPENAME##_setSize(keyArray, numElements)) || \
435 (valueArray && !VALUEARRAYTYPENAME##_setSize(valueArray, numElements))) \
438 for (slotNdx = 0; slotNdx < hash->slotTableSize; slotNdx++) \
440 const HASHTYPENAME##Slot* slot = hash->slotTable[slotNdx]; \
444 for (elemNdx = 0; elemNdx < slot->numUsed; elemNdx++) \
447 KEYARRAYTYPENAME##_set(keyArray, arrayNdx, slot->keys[elemNdx]); \
449 VALUEARRAYTYPENAME##_set(valueArray, arrayNdx, slot->values[elemNdx]); \
452 slot = slot->nextSlot; \
455 DE_ASSERT(arrayNdx == numElements); \
458 struct HASHTYPENAME##_##KEYARRAYTYPENAME##_##VALUEARRAYTYPENAME##_implement_dummy { int dummy; }
460 #endif /* _DEPOOLHASH_H */