• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file cstl_hash.c
3  * @copyright Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15 
16  * @brief cstl_hash 实现源码
17  * @details 哈希表实现源码
18  * @date 2021-05-14
19  * @version v0.1.0
20  * *******************************************************************************************
21  * @par 修改日志:
22  * <table>
23  * <tr><th>Date        <th>Version  <th>Author    <th>Description
24  * </table>
25  * *******************************************************************************************
26  */
27 
28 #include "cstl_rawlist.h"
29 #include "securec.h"
30 #include "cstl_public_inner.h"
31 #include "cstl_hash.h"
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif /* __cplusplus */
36 
37 #define CSTL_HASH_OPTION3 3
38 #define CSTL_HASH_OPTION2 2
39 #define CSTL_HASH_OPTION1 1
40 
41 struct TagHashNode {
42     CstlRawListNode  node;            /**< 链表node */
43     uintptr_t        key;             /**< key或保存key的地址 */
44     uintptr_t        value;           /**< value或保存value的地址 */
45 };
46 
47 typedef struct TagHashNode CstlHashNode;
48 
49 struct CstlHashInfo {
50     CstlDupFreeFuncPair keyFunc;     /**< key拷贝、释放函数对 */
51     CstlDupFreeFuncPair valueFunc;   /**< value拷贝、释放函数对 */
52     CstlHashMatchFunc matchFunc;     /**< 匹配函数 */
53     CstlHashCodeCalcFunc hashFunc;   /**< 哈希函数 */
54     size_t bucketSize;               /**< Hash表大小 */
55     size_t hashCount;                /**< Hash表中表项的个数 */
56     CstlRawList listArray[0];        /**< 链表控制块数组 */
57 };
58 
59 /* murmurhash算法 */
60 /* 定义常量 */
61 #define HASH_VC1 0xCC9E2D51
62 #define HASH_VC2 0x1B873593
63 #define HASH_HC1 0xE6546B64
64 #define HASH_HC2 0x85EBCA6B
65 #define HASH_HC3 0xC2B2AE35
66 #define HASH_HC4 5
67 
68 #define CHAR_BIT 8
69 #define CHAR_FOR_PER_LOOP 4
70 #define HASH_V_ROTATE 15
71 #define HASH_H_ROTATE 13
72 #define SYS_BUS_WIDTH sizeof(size_t)
73 #define HASH_SEED 0x3B9ACA07        /* 大质数1000000007,种子可以随机也可以指定 */
74 
75 enum CstlByte {
76     ONE_BYTE = 1,
77     TWO_BYTE = 2,
78 };
79 
80 enum CstlShiftBit {
81     SHIFT8 = 8,
82     SHIFT13 = 13,
83     SHIFT16 = 16,
84     SHIFT24 = 24
85 };
86 
87 CstlHashIterator CstlHashPrev(const CstlHash *hash, CstlHashIterator hashNode);
88 
CstlHashRotate(size_t v,uint32_t offset)89 CSTL_STATIC size_t CstlHashRotate(size_t v, uint32_t offset)
90 {
91     return ((v << offset) | (v >> (SYS_BUS_WIDTH * CHAR_BIT - offset)));
92 }
93 
CstlHashMixV(size_t v)94 CSTL_STATIC size_t CstlHashMixV(size_t v)
95 {
96     v = v * HASH_VC1;
97     v = CstlHashRotate(v, HASH_V_ROTATE);
98     v = v * HASH_VC2;
99 
100     return v;
101 }
102 
CstlHashMixH(size_t h,size_t v)103 CSTL_STATIC size_t CstlHashMixH(size_t h, size_t v)
104 {
105     size_t res = h;
106 
107     res ^= v;
108     res = CstlHashRotate(res, HASH_H_ROTATE);
109     res = res * HASH_HC4 + HASH_HC1;
110 
111     return res;
112 }
113 
CstlHashCodeCalc(void * key,size_t keySize)114 CSTL_STATIC size_t CstlHashCodeCalc(void *key, size_t keySize)
115 {
116     uint8_t *tmpKey = (uint8_t *)key;
117     size_t i = 0;
118     size_t v;
119     size_t h = HASH_SEED;
120     uint8_t c0, c1, c2, c3;
121     size_t tmpLen = keySize - keySize % CHAR_FOR_PER_LOOP;
122 
123     while ((i + CHAR_FOR_PER_LOOP) <= tmpLen) {
124         c0 = tmpKey[i++];
125         c1 = tmpKey[i++];
126         c2 = tmpKey[i++];
127         c3 = tmpKey[i++];
128 
129         v = (size_t)c0 | ((size_t)c1 << SHIFT8) |
130             ((size_t)c2 << SHIFT16) | ((size_t)c3 << SHIFT24);
131         v = CstlHashMixV(v);
132         h = CstlHashMixH(h, v);
133     }
134 
135     v = 0;
136 
137     switch (keySize & CSTL_HASH_OPTION3) {
138         case CSTL_HASH_OPTION3:
139             v ^= ((size_t)tmpKey[i + TWO_BYTE] << SHIFT16);
140             /* (keySize % 4)等于3,fallthrough,其他分支类似。 */
141             /* fall-through */
142         case CSTL_HASH_OPTION2:
143             v ^= ((size_t)tmpKey[i + ONE_BYTE] << SHIFT8);
144             /* fall-through */
145         case CSTL_HASH_OPTION1:
146             v ^= tmpKey[i];
147             v = CstlHashMixV(v);
148             h ^= v;
149             break;
150         default:
151             break;
152     }
153 
154     h ^= h >> SHIFT16;
155 
156     h *= HASH_HC2;
157     h ^= h >> SHIFT13;
158     h *= HASH_HC3;
159     h ^= h >> SHIFT16;
160 
161     return h;
162 }
163 
164 /* 内部接口定义 */
CstlHashHookRegister(CstlHash * hash,CstlHashCodeCalcFunc hashFunc,CstlHashMatchFunc matchFunc,CstlDupFreeFuncPair * keyFunc,CstlDupFreeFuncPair * valueFunc)165 CSTL_STATIC void CstlHashHookRegister(CstlHash *hash,
166                                       CstlHashCodeCalcFunc hashFunc,
167                                       CstlHashMatchFunc matchFunc,
168                                       CstlDupFreeFuncPair *keyFunc,
169                                       CstlDupFreeFuncPair *valueFunc)
170 {
171     CstlDupFreeFuncPair *hashKeyFunc = &hash->keyFunc;
172     CstlDupFreeFuncPair *hashValueFunc = &hash->valueFunc;
173 
174     if (hashFunc == NULL) {
175         hash->hashFunc = CstlHashCodeCalcInt;
176     } else {
177         hash->hashFunc = hashFunc;
178     }
179 
180     if (matchFunc == NULL) {
181         hash->matchFunc = CstlHashMatchInt;
182     } else {
183         hash->matchFunc = matchFunc;
184     }
185 
186     if (keyFunc == NULL) {
187         hashKeyFunc->dupFunc = NULL;
188         hashKeyFunc->freeFunc = NULL;
189     } else {
190         hashKeyFunc->dupFunc = keyFunc->dupFunc;
191         hashKeyFunc->freeFunc = keyFunc->freeFunc;
192     }
193 
194     if (valueFunc == NULL) {
195         hashValueFunc->dupFunc = NULL;
196         hashValueFunc->freeFunc = NULL;
197     } else {
198         hashValueFunc->dupFunc = valueFunc->dupFunc;
199         hashValueFunc->freeFunc = valueFunc->freeFunc;
200     }
201 }
202 
CstlHashIterEndGet(const CstlHash * hash)203 CSTL_STATIC inline CstlHashIterator CstlHashIterEndGet(const CstlHash *hash)
204 {
205     return (CstlHashIterator)(uintptr_t)(&hash->listArray[hash->bucketSize].head);
206 }
207 
CstlHashNodeCreate(const CstlHash * hash,uintptr_t key,size_t keySize,uintptr_t value,size_t valueSize)208 CSTL_STATIC CstlHashNode *CstlHashNodeCreate(const CstlHash *hash, uintptr_t key, size_t keySize,
209                                              uintptr_t value, size_t valueSize)
210 {
211     uintptr_t tmpKey;
212     uintptr_t tmpValue;
213     CstlHashNode *hashNode;
214     void *tmpPtr;
215 
216     hashNode = (CstlHashNode *)malloc(sizeof(CstlHashNode));
217     if (hashNode == NULL) {
218         CSTL_PRINTF("[Cstlhash]: malloc failed. File = %s, line = %d.\r\n", __FILE__, __LINE__);
219         return NULL;
220     }
221 
222     if (hash->keyFunc.dupFunc != NULL) {
223         tmpPtr = hash->keyFunc.dupFunc((void *)key, keySize);
224         tmpKey = (uintptr_t)tmpPtr;
225         if (tmpKey == (uintptr_t)NULL) {
226             /* 考虑用户返回失败的场景 */
227             free(hashNode);
228             return NULL;
229         }
230     } else {
231         tmpKey = key;
232     }
233 
234     if (hash->valueFunc.dupFunc != NULL) {
235         tmpPtr = hash->valueFunc.dupFunc((void *)value, valueSize);
236         tmpValue = (uintptr_t)tmpPtr;
237         if (tmpValue == (uintptr_t)NULL) {
238             /* 考虑用户返回失败的场景 */
239             if (hash->keyFunc.freeFunc != NULL) {
240                 hash->keyFunc.freeFunc((void *)tmpKey);
241             }
242 
243             free(hashNode);
244             return NULL;
245         }
246     } else {
247         tmpValue = value;
248     }
249 
250     hashNode->key = tmpKey;
251     hashNode->value = tmpValue;
252 
253     return hashNode;
254 }
255 
CstlHashFindNode(const CstlRawList * list,uintptr_t key,CstlHashMatchFunc matchFunc)256 CSTL_STATIC CstlHashNode *CstlHashFindNode(const CstlRawList *list, uintptr_t key, CstlHashMatchFunc matchFunc)
257 {
258     CstlHashNode *hashNode;
259     CstlRawListNode *rawListNode;
260 
261     for (rawListNode = CstlRawListFront(list); rawListNode != NULL; rawListNode = CstlRawListNext(list, rawListNode)) {
262         hashNode = CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
263         if (matchFunc(hashNode->key, key)) {
264             return hashNode;
265         }
266     }
267 
268     return NULL;
269 }
270 
CstlHashFront(const CstlHash * hash)271 CSTL_STATIC CstlHashIterator CstlHashFront(const CstlHash *hash)
272 {
273     uint32_t i = 0;
274     const CstlRawList *list;
275     CstlRawListNode *rawListNode;
276 
277     while (i < hash->bucketSize) {
278         list = &hash->listArray[i];
279         rawListNode = CstlRawListFront(list);
280         if (rawListNode != NULL) {
281             return CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
282         }
283 
284         i++;
285     }
286 
287     return CstlHashIterEndGet(hash);
288 }
289 
CstlHashNext(const CstlHash * hash,CstlHashIterator hashNode)290 CSTL_STATIC CstlHashIterator CstlHashNext(const CstlHash *hash, CstlHashIterator hashNode)
291 {
292     size_t i;
293     size_t hashCode;
294     const CstlRawList *list;
295     CstlRawListNode *rawListNode;
296 
297     hashCode = hash->hashFunc(hashNode->key, hash->bucketSize);
298     if (hashCode >= hash->bucketSize) {
299         CSTL_PRINTF("[Cstlhash]: hashCode is invalid.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
300         return CstlHashIterEndGet(hash);
301     }
302 
303     list = hash->listArray + hashCode;
304     rawListNode = CstlRawListNext(list, &hashNode->node);
305     if (rawListNode != NULL) {
306         return CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
307     }
308 
309     for (i = hashCode + 1; i < hash->bucketSize; ++i) {
310         list = &hash->listArray[i];
311         rawListNode = CstlRawListFront(list);
312         if (rawListNode != NULL) {
313             return CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
314         }
315     }
316 
317     return CstlHashIterEndGet(hash);
318 }
319 
CstlHashPrev(const CstlHash * hash,CstlHashIterator hashNode)320 CstlHashIterator CstlHashPrev(const CstlHash *hash, CstlHashIterator hashNode)
321 {
322     ssize_t i;
323     size_t hashCode;
324     const CstlRawList *list;
325     CstlRawListNode *rawListNode;
326 
327     hashCode = hash->hashFunc(hashNode->key, hash->bucketSize);
328     if (hashCode >= hash->bucketSize) {
329         CSTL_PRINTF("[Cstlhash]: hashCode is invalid.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
330         return CstlHashIterEndGet(hash);
331     }
332 
333     list = hash->listArray + hashCode;
334     rawListNode = CstlRawListPrev(list, &hashNode->node);
335     if (rawListNode != NULL) {
336         return CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
337     }
338 
339     for (i = (ssize_t)(hashCode - 1); i >= 0; --i) {
340         list = &hash->listArray[i];
341         rawListNode = CstlRawListBack(list);
342         if (rawListNode != NULL) {
343             return CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
344         }
345     }
346 
347     return CstlHashIterEndGet(hash);
348 }
349 
CstlHashNodeFree(CstlHash * hash,CstlHashNode * node)350 CSTL_STATIC void CstlHashNodeFree(CstlHash *hash, CstlHashNode *node)
351 {
352     CstlFreeFunc keyFreeFunc = hash->keyFunc.freeFunc;
353     CstlFreeFunc valueFreeFunc = hash->valueFunc.freeFunc;
354 
355     if (keyFreeFunc != NULL) {
356         keyFreeFunc((void *)node->key);
357     }
358 
359     if (valueFreeFunc != NULL) {
360         valueFreeFunc((void *)node->value);
361     }
362 
363     free(node);
364 }
365 
CstlHashCodeCalcInt(uintptr_t key,size_t bktSize)366 __attribute__((visibility("default"))) size_t CstlHashCodeCalcInt(uintptr_t key, size_t bktSize)
367 {
368     size_t hashCode = CstlHashCodeCalc(&key, sizeof(key));
369 
370     return hashCode % bktSize;
371 }
372 
CstlHashMatchInt(uintptr_t key1,uintptr_t key2)373 __attribute__((visibility("default"))) bool CstlHashMatchInt(uintptr_t key1, uintptr_t key2)
374 {
375     return key1 == key2;
376 }
377 
CstlHashCodeCalcStr(uintptr_t key,size_t bktSize)378 __attribute__((visibility("default"))) size_t CstlHashCodeCalcStr(uintptr_t key, size_t bktSize)
379 {
380     char *tmpKey = (char *)key;
381     size_t hashCode = CstlHashCodeCalc(tmpKey, strlen(tmpKey));
382 
383     return hashCode % bktSize;
384 }
385 
CstlHashMatchStr(uintptr_t key1,uintptr_t key2)386 __attribute__((visibility("default"))) bool CstlHashMatchStr(uintptr_t key1, uintptr_t key2)
387 {
388     char *tkey1 = (char *)key1;
389     char *tkey2 = (char *)key2;
390 
391     if (strcmp(tkey1, tkey2) == 0) {
392         return true;
393     }
394 
395     return false;
396 }
397 
CstlHashCreate(size_t bktSize,CstlHashCodeCalcFunc hashFunc,CstlHashMatchFunc matchFunc,CstlDupFreeFuncPair * keyFunc,CstlDupFreeFuncPair * valueFunc)398 __attribute__((visibility("default"))) CstlHash *CstlHashCreate(size_t bktSize,
399                                                                 CstlHashCodeCalcFunc hashFunc,
400                                                                 CstlHashMatchFunc matchFunc,
401                                                                 CstlDupFreeFuncPair *keyFunc,
402                                                                 CstlDupFreeFuncPair *valueFunc)
403 {
404     size_t i;
405     size_t size;
406     CstlHash *hash;
407     CstlRawList *listAddr;
408     if (bktSize == 0U) {
409         CSTL_PRINTF("[Cstlhash]: bktSize is 0.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
410         return NULL;
411     }
412 
413     size = (bktSize + 1) * sizeof(CstlRawList);
414     if (IsMultiOverflow((bktSize + 1), sizeof(CstlRawList)) || IsAddOverflow(size, sizeof(CstlHash))) {
415         CSTL_PRINTF("[Cstlhash]: bktSize is too big.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
416         return NULL;
417     }
418 
419     size += sizeof(CstlHash);
420     hash = (CstlHash *)malloc(size);
421     if (hash == NULL) {
422         CSTL_PRINTF("[Cstlhash]: malloc failed.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
423         return NULL;
424     }
425 
426     (void)memset_s(hash, size, 0, size);
427     hash->bucketSize = bktSize;
428     CstlHashHookRegister(hash, hashFunc, matchFunc, keyFunc, valueFunc);
429 
430     listAddr = hash->listArray;
431     for (i = 0; i <= bktSize; ++i) {
432         CstlRawListInit(listAddr + i, NULL);
433     }
434 
435     return hash;
436 }
437 
CstlHashInsertNode(CstlHash * hash,CstlRawList * rawList,const CstlUserData * inputKey,const CstlUserData * inputValue)438 CSTL_STATIC int32_t CstlHashInsertNode(CstlHash *hash, CstlRawList *rawList,
439                                        const CstlUserData *inputKey, const CstlUserData *inputValue)
440 {
441     CstlHashNode *hashNode =
442         CstlHashNodeCreate(hash, inputKey->inputData, inputKey->dataSize, inputValue->inputData, inputValue->dataSize);
443     if (hashNode == NULL) {
444         CSTL_PRINTF("[Cstlhash]: hashNode create failed.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
445         return CSTL_ERROR;
446     }
447 
448     CstlRawListPushBack(rawList, &hashNode->node);
449     hash->hashCount++;
450 
451     return CSTL_OK;
452 }
453 
CstlHashUpdateNode(CstlHash * hash,CstlHashNode * node,uintptr_t value,size_t valueSize)454 static int32_t CstlHashUpdateNode(CstlHash *hash, CstlHashNode *node, uintptr_t value, size_t valueSize)
455 {
456     uintptr_t tmpValue;
457     void *tmpPtr;
458 
459     if (hash->valueFunc.dupFunc != NULL) {
460         tmpPtr = hash->valueFunc.dupFunc((void *)value, valueSize);
461         tmpValue = (uintptr_t)tmpPtr;
462         if (tmpValue == (uintptr_t)NULL) {
463             /* 考虑用户返回失败的场景 */
464             return CSTL_ERROR;
465         }
466 
467         if (hash->valueFunc.freeFunc != NULL) {
468             hash->valueFunc.freeFunc((void *)node->value);
469         }
470     } else {
471         tmpValue = value;
472     }
473 
474     node->value = tmpValue;
475 
476     return CSTL_OK;
477 }
478 
CstlHashCodeCheck(const CstlHash * hash,uintptr_t key,size_t * hashCode)479 CSTL_STATIC inline int32_t CstlHashCodeCheck(const CstlHash *hash, uintptr_t key, size_t *hashCode)
480 {
481     if (hash == NULL) {
482         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
483         return CSTL_ERROR;
484     }
485 
486     *hashCode = hash->hashFunc(key, hash->bucketSize);
487     if (*hashCode >= hash->bucketSize) {
488         CSTL_PRINTF("[Cstlhash]: hashCode is invalid.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
489         return CSTL_ERROR;
490     }
491 
492     return CSTL_OK;
493 }
494 
CstlHashInsert(CstlHash * hash,uintptr_t key,size_t keySize,uintptr_t value,size_t valueSize)495 __attribute__((visibility("default"))) int32_t CstlHashInsert(CstlHash *hash, uintptr_t key, size_t keySize,
496                                                               uintptr_t value, size_t valueSize)
497 {
498     int32_t ret;
499     size_t hashCode;
500     CstlHashNode *hashNode;
501     CstlRawList *rawList;
502     CstlUserData inputKey;
503     CstlUserData inputValue;
504 
505     ret = CstlHashCodeCheck(hash, key, &hashCode);
506     if (ret != CSTL_OK) {
507         return CSTL_ERROR;
508     }
509 
510     rawList = &hash->listArray[hashCode];
511     hashNode = CstlHashFindNode(rawList, key, hash->matchFunc);
512     if (hashNode != NULL) {
513         CSTL_PRINTF("[Cstlhash]: key is exist.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
514         return CSTL_ERROR;
515     }
516 
517     inputKey.inputData = key;
518     inputKey.dataSize = keySize;
519     inputValue.inputData = value;
520     inputValue.dataSize = valueSize;
521 
522     return CstlHashInsertNode(hash, rawList, &inputKey, &inputValue);
523 }
524 
CstlHashPut(CstlHash * hash,uintptr_t key,size_t keySize,uintptr_t value,size_t valueSize)525 __attribute__((visibility("default"))) int32_t CstlHashPut(CstlHash *hash, uintptr_t key, size_t keySize,
526                                                            uintptr_t value, size_t valueSize)
527 {
528     int32_t ret;
529     size_t hashCode;
530     CstlRawList *rawList;
531     CstlHashNode *hashNode;
532     CstlUserData inputKey;
533     CstlUserData inputValue;
534 
535     ret = CstlHashCodeCheck(hash, key, &hashCode);
536     if (ret != CSTL_OK) {
537         return CSTL_ERROR;
538     }
539 
540     rawList = &hash->listArray[hashCode];
541     hashNode = CstlHashFindNode(rawList, key, hash->matchFunc);
542     if (hashNode != NULL) {
543         return CstlHashUpdateNode(hash, hashNode, value, valueSize);
544     }
545 
546     inputKey.inputData = key;
547     inputKey.dataSize = keySize;
548     inputValue.inputData = value;
549     inputValue.dataSize = valueSize;
550 
551     return CstlHashInsertNode(hash, rawList, &inputKey, &inputValue);
552 }
553 
CstlHashAt(const CstlHash * hash,uintptr_t key,uintptr_t * value)554 __attribute__((visibility("default"))) int32_t CstlHashAt(const CstlHash *hash, uintptr_t key, uintptr_t *value)
555 {
556     CstlHashNode *hashNode = CstlHashFind(hash, key);
557 
558     if (hashNode == CstlHashIterEndGet(hash)) {
559         return CSTL_ERROR;
560     }
561 
562     *value = hashNode->value;
563 
564     return CSTL_OK;
565 }
566 
CstlHashFind(const CstlHash * hash,uintptr_t key)567 __attribute__((visibility("default"))) CstlHashIterator CstlHashFind(const CstlHash *hash, uintptr_t key)
568 {
569     int32_t ret;
570     size_t hashCode;
571     CstlHashNode *hashNode;
572 
573     ret = CstlHashCodeCheck(hash, key, &hashCode);
574     if (ret != CSTL_OK) {
575         return hash == NULL ? NULL : CstlHashIterEndGet(hash);
576     }
577 
578     hashNode = CstlHashFindNode(&hash->listArray[hashCode], key, hash->matchFunc);
579     if (hashNode == NULL) {
580         CSTL_PRINTF("[Cstlhash]: key is not exist.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
581         return CstlHashIterEndGet(hash);
582     }
583 
584     return hashNode;
585 }
586 
CstlHashEmpty(const CstlHash * hash)587 __attribute__((visibility("default"))) bool CstlHashEmpty(const CstlHash *hash)
588 {
589     if ((hash == NULL) || (hash->hashCount == 0U)) {
590         return true;
591     }
592 
593     return false;
594 }
595 
CstlHashSize(const CstlHash * hash)596 __attribute__((visibility("default"))) size_t CstlHashSize(const CstlHash *hash)
597 {
598     if (hash == NULL) {
599         return 0;
600     }
601 
602     return hash->hashCount;
603 }
604 
CstlHashErase(CstlHash * hash,uintptr_t key)605 __attribute__((visibility("default"))) CstlHashIterator CstlHashErase(CstlHash *hash, uintptr_t key)
606 {
607     size_t hashCode;
608     CstlHashNode *hashNode;
609     CstlHashNode *nextHashNode;
610     CstlHashMatchFunc matchFunc;
611     CstlHashCodeCalcFunc hashFunc;
612 
613     if (hash == NULL) {
614         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
615         return NULL;
616     }
617 
618     hashFunc = hash->hashFunc;
619     hashCode = hashFunc(key, hash->bucketSize);
620     if (hashCode >= hash->bucketSize) {
621         CSTL_PRINTF("[Cstlhash]: hashCode is invalid.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
622         return CstlHashIterEndGet(hash);
623     }
624 
625     matchFunc = hash->matchFunc;
626     hashNode = CstlHashFindNode(&hash->listArray[hashCode], key, matchFunc);
627     if (hashNode == NULL) {
628         return CstlHashIterEndGet(hash);
629     }
630 
631     nextHashNode = CstlHashNext(hash, hashNode);
632     CstlRawListErase(&hash->listArray[hashCode], &hashNode->node);
633     CstlHashNodeFree(hash, hashNode);
634     --hash->hashCount;
635 
636     return nextHashNode;
637 }
638 
CstlHashClear(CstlHash * hash)639 __attribute__((visibility("default"))) void CstlHashClear(CstlHash *hash)
640 {
641     uint32_t i;
642     CstlRawList *list;
643     CstlHashNode *hashNode;
644     CstlRawListNode *rawListNode;
645 
646     if (hash == NULL) {
647         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
648         return;
649     }
650 
651     for (i = 0; i < hash->bucketSize; ++i) {
652         list = &hash->listArray[i];
653         while (!CstlRawListEmpty(list)) {
654             rawListNode = CstlRawListFront(list);
655             hashNode = CSTL_CONTAINER_OF(rawListNode, CstlHashNode, node);
656             CstlRawListErase(list, rawListNode);
657             CstlHashNodeFree(hash, hashNode);
658         }
659     }
660 
661     hash->hashCount = 0;
662 }
663 
CstlHashDestory(CstlHash * hash)664 __attribute__((visibility("default"))) void CstlHashDestory(CstlHash *hash)
665 {
666     if (hash == NULL) {
667         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
668         return;
669     }
670 
671     CstlHashClear(hash);
672     free(hash);
673 }
674 
CstlHashIterBegin(const CstlHash * hash)675 __attribute__((visibility("default"))) CstlHashIterator CstlHashIterBegin(const CstlHash *hash)
676 {
677     if (hash == NULL) {
678         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
679         return NULL;
680     }
681 
682     return CstlHashFront(hash);
683 }
684 
CstlHashIterEnd(const CstlHash * hash)685 __attribute__((visibility("default"))) CstlHashIterator CstlHashIterEnd(const CstlHash *hash)
686 {
687     if (hash == NULL) {
688         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
689         return NULL;
690     }
691 
692     return CstlHashIterEndGet(hash);
693 }
694 
CstlHashIterNext(const CstlHash * hash,CstlHashIterator it)695 __attribute__((visibility("default"))) CstlHashIterator CstlHashIterNext(const CstlHash *hash, CstlHashIterator it)
696 {
697     if ((hash == NULL) || (it == CstlHashIterEnd(hash))) {
698         CSTL_PRINTF("[Cstlhash]: hash is NULL.  File = %s, line = %d.\r\n", __FILE__, __LINE__);
699         return CstlHashIterEnd(hash);
700     }
701 
702     return CstlHashNext(hash, it);
703 }
704 
CstlHashIterKey(const CstlHash * hash,CstlHashIterator it)705 __attribute__((visibility("default"))) uintptr_t CstlHashIterKey(const CstlHash *hash, CstlHashIterator it)
706 {
707     if (it == CstlHashIterEnd(hash)) {
708         return 0;
709     }
710 
711     return it->key;
712 }
713 
CstlHashIterValue(const CstlHash * hash,CstlHashIterator it)714 __attribute__((visibility("default"))) uintptr_t CstlHashIterValue(const CstlHash *hash, CstlHashIterator it)
715 {
716     if (it == CstlHashIterEnd(hash)) {
717         return 0;
718     }
719 
720     return it->value;
721 }
722 
723 #ifdef __cplusplus
724 }
725 #endif /* __cplusplus */