• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hash_table.h"
17 #include <securec.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #define HASH_TRUE 1
22 #define HASH_FALSE 0
23 
24 #define HASH_CAP_LOAD_FACTOR 5
25 #define HASH_CAP_GROWTH_FACTOR 10
26 #define HASH_CALC_CODE_CALC 5
27 
28 const int HASH_DEFAULT_VALUE = 5381;
29 const int HASH_CALC_MODE_HASH = 1;
30 
31 size_t HashCode(uintptr_t rawKey, size_t keySize);
32 int HashCompare(uintptr_t firstKey, uintptr_t secondKey, size_t keySize);
33 size_t Hash(const HashTable *table, uintptr_t key);
34 int HashEquals(const HashTable *table, uintptr_t firstKey, uintptr_t secondKey);
35 int HashShouldGrow(HashTable *table);
36 int HashShouldShrink(HashTable *table);
37 int CapExtend(HashTable *table, size_t miniCapacity);
38 HashNode *HashCreateNode(HashTable *table, uintptr_t key, uintptr_t value, HashNode *next);
39 int HashPushFront(HashTable *table, size_t index, uintptr_t key, uintptr_t value);
40 void DestroyHashNode(HashNode *node);
41 int HashAdjustCapacity(HashTable *table);
42 int HashAllocate(HashTable *table, size_t capacity);
43 void HashRehash(HashTable *table, HashNode **old, size_t oldCapacity);
44 
CreateHashTable(HashTable * table,size_t keySize,size_t valueSize,size_t capacity)45 int CreateHashTable(HashTable *table, size_t keySize, size_t valueSize, size_t capacity)
46 {
47     if (table == 0) {
48         return HASH_ERROR;
49     }
50 
51     if (capacity < HASH_MINI_CAPACITY) {
52         capacity = HASH_MINI_CAPACITY;
53     }
54 
55     if (HashAllocate(table, capacity) == HASH_ERROR) {
56         return HASH_ERROR;
57     }
58 
59     table->keySize = keySize;
60     table->valueSize = valueSize;
61     table->hash = HashCode;
62     table->compare = HashCompare;
63     table->size = 0;
64     return HASH_SUCCESS;
65 }
66 
DestroyHashTable(HashTable * table)67 int DestroyHashTable(HashTable *table)
68 {
69     if (!Initialized(table)) {
70         return HASH_ERROR;
71     }
72     for (size_t current = 0; current < table->capacity; ++current) {
73         HashNode *node = table->nodes[current];
74         while (node) {
75             HashNode *next = node->next;
76             DestroyHashNode(node);
77             node = next;
78         }
79     }
80     free(table->nodes);
81     table->nodes = NULL;
82     return HASH_SUCCESS;
83 }
84 
Insert(HashTable * table,uintptr_t key,uintptr_t value)85 int Insert(HashTable *table, uintptr_t key, uintptr_t value)
86 {
87     if (!Initialized(table)) {
88         return HASH_ERROR;
89     }
90     if (key == 0) {
91         return HASH_ERROR;
92     }
93     if (HashShouldGrow(table)) {
94         HashAdjustCapacity(table);
95     }
96     size_t index = Hash(table, key);
97     int ret = HASH_INSERTED;
98     for (HashNode *node = table->nodes[index]; node; node = node->next) {
99         if (HashEquals(table, key, node->key)) {
100             ret = HASH_UPDATED;
101         }
102         if (ret == HASH_UPDATED && memcpy_s((void *)node->value, table->valueSize,
103             (void *)value, table->valueSize) != EOK) {
104             return HASH_ERROR;
105         }
106         if (ret == HASH_UPDATED) {
107             return HASH_UPDATED;
108         }
109     }
110     if (HashPushFront(table, index, key, value) == HASH_ERROR) {
111         return HASH_ERROR;
112     }
113     ++table->size;
114     return ret;
115 }
116 
ContainsKey(const HashTable * table,uintptr_t key)117 int ContainsKey(const HashTable *table, uintptr_t key)
118 {
119     if (!Initialized(table)) {
120         return HASH_FALSE;
121     }
122     if (key == 0) {
123         return HASH_FALSE;
124     }
125 
126     size_t index = Hash(table, key);
127     for (HashNode *node = table->nodes[index]; node; node = node->next) {
128         if (HashEquals(table, key, node->key)) {
129             return HASH_TRUE;
130         }
131     }
132     return HASH_FALSE;
133 }
134 
At(HashTable * table,uintptr_t key)135 uintptr_t At(HashTable *table, uintptr_t key)
136 {
137     if (table == 0) {
138         return 0;
139     }
140     if (key == 0) {
141         return 0;
142     }
143 
144     size_t index = Hash(table, key);
145     for (HashNode *node = table->nodes[index]; node; node = node->next) {
146         if (HashEquals(table, key, node->key)) {
147             return node->value;
148         }
149     }
150     return 0;
151 }
152 
Remove(HashTable * table,uintptr_t key)153 int Remove(HashTable *table, uintptr_t key)
154 {
155     if (table == 0) {
156         return HASH_ERROR;
157     }
158     if (key == 0) {
159         return HASH_ERROR;
160     }
161 
162     size_t index = Hash(table, key);
163     HashNode *node = table->nodes[index];
164 
165     for (HashNode *previous = NULL; node; previous = node, node = node->next) {
166         if (HashEquals(table, key, node->key)) {
167             if (previous) {
168                 previous->next = node->next;
169             } else {
170                 table->nodes[index] = node->next;
171             }
172 
173             DestroyHashNode(node);
174             --table->size;
175             int shouldShrink = 0;
176             if (HashShouldShrink(table)) {
177                 shouldShrink = 1;
178             }
179             if (shouldShrink && HashAdjustCapacity(table) == HASH_ERROR) {
180                 return HASH_ERROR;
181             }
182             return HASH_SUCCESS;
183         }
184     }
185     return HASH_KEY_NOT_FOUND;
186 }
187 
ClearAll(HashTable * table)188 int ClearAll(HashTable *table)
189 {
190     if (table == 0 || table->nodes == 0) {
191         return HASH_ERROR;
192     }
193     if (table->size == 0) {
194         return HASH_SUCCESS;
195     }
196     if (DestroyHashTable(table) == HASH_ERROR || HashAllocate(table, HASH_MINI_CAPACITY) == HASH_ERROR) {
197         return HASH_ERROR;
198     }
199     table->size = 0;
200     return HASH_SUCCESS;
201 }
202 
Empty(const HashTable * table)203 int Empty(const HashTable *table)
204 {
205     if (table == 0) {
206         return HASH_ERROR;
207     }
208     if (table->size == 0) {
209         return HASH_SUCCESS;
210     }
211     return HASH_NOT_EMPTY;
212 }
213 
Initialized(const HashTable * table)214 int Initialized(const HashTable *table)
215 {
216     if (table && table->capacity && table->keySize && table->valueSize && table->hash && table->compare) {
217         return HASH_TRUE;
218     }
219     return HASH_FALSE;
220 }
221 
CapExtend(HashTable * table,size_t miniCapacity)222 int CapExtend(HashTable *table, size_t miniCapacity)
223 {
224     if (!Initialized(table)) {
225         return HASH_ERROR;
226     }
227 
228     if (miniCapacity > table->threshold) {
229         return Resize(table, miniCapacity / HASH_CAP_LOAD_FACTOR);
230     }
231     return HASH_SUCCESS;
232 }
233 
HashCompare(uintptr_t firstKey,uintptr_t secondKey,size_t keySize)234 int HashCompare(uintptr_t firstKey, uintptr_t secondKey, size_t keySize)
235 {
236     if (memcmp((void *)firstKey, (void *)secondKey, keySize) == 0) {
237         return 0;
238     }
239     return 1;
240 }
241 
HashCode(uintptr_t rawKey,size_t keySize)242 size_t HashCode(uintptr_t rawKey, size_t keySize)
243 {
244     size_t hash = HASH_DEFAULT_VALUE;
245     const char *key = (char *)rawKey;
246 
247     for (size_t byte = 0; byte < keySize; ++byte) {
248         hash = ((hash << HASH_CALC_CODE_CALC) + hash) ^ key[byte];
249     }
250     return hash;
251 }
252 
Hash(const HashTable * table,uintptr_t key)253 size_t Hash(const HashTable *table, uintptr_t key)
254 {
255     if (HASH_CALC_MODE_HASH) {
256         return table->hash(key, table->keySize) % table->capacity;
257     }
258     return table->hash(key, table->keySize) & table->capacity;
259 }
260 
HashEquals(const HashTable * table,uintptr_t firstKey,uintptr_t secondKey)261 int HashEquals(const HashTable *table, uintptr_t firstKey, uintptr_t secondKey)
262 {
263     if (table->compare(firstKey, secondKey, table->keySize) == 0) {
264         return HASH_TRUE;
265     }
266     return HASH_FALSE;
267 }
268 
HashShouldGrow(HashTable * table)269 int HashShouldGrow(HashTable *table)
270 {
271     if (table->size == table->capacity) {
272         return HASH_TRUE;
273     }
274     return HASH_FALSE;
275 }
276 
HashShouldShrink(HashTable * table)277 int HashShouldShrink(HashTable *table)
278 {
279     static size_t capSszie = sizeof(size_t);
280     if (table->size == table->capacity / capSszie) {
281         return HASH_TRUE;
282     }
283     return HASH_FALSE;
284 }
285 
HashCreateNode(HashTable * table,uintptr_t key,uintptr_t value,HashNode * next)286 HashNode *HashCreateNode(HashTable *table, uintptr_t key, uintptr_t value, HashNode *next)
287 {
288     HashNode *node = (HashNode *)calloc(1, sizeof(HashNode));
289     if (node == 0) {
290         return 0;
291     }
292     int flag = 0;
293     do {
294         node->key = (uintptr_t)calloc(table->keySize, sizeof(char));
295         node->value = (uintptr_t)calloc(table->valueSize, sizeof(char));
296         if (node->key == 0 || node->value == 0) {
297             break;
298         }
299         if (memcpy_s((void *)node->key, table->keySize, (void *)key, table->keySize) != EOK ||
300             memcpy_s((void *)node->value, table->valueSize, (void *)value, table->valueSize) != EOK) {
301             break;
302         }
303         flag += 1;
304     } while (0);
305     if (flag == 0) {
306         free((void *)node->key);
307         free((void *)node->value);
308         free(node);
309         node = NULL;
310         return 0;
311     }
312     node->next = next;
313     return node;
314 }
315 
HashPushFront(HashTable * table,size_t index,uintptr_t key,uintptr_t value)316 int HashPushFront(HashTable *table, size_t index, uintptr_t key, uintptr_t value)
317 {
318     table->nodes[index] = HashCreateNode(table, key, value, table->nodes[index]);
319     if (table->nodes[index] != NULL) {
320         return HASH_SUCCESS;
321     }
322     return HASH_ERROR;
323 }
324 
DestroyHashNode(HashNode * node)325 void DestroyHashNode(HashNode *node)
326 {
327     free((void *)node->key);
328     free((void *)node->value);
329     free(node);
330     node = NULL;
331 }
332 
HashAdjustCapacity(HashTable * table)333 int HashAdjustCapacity(HashTable *table)
334 {
335     return Resize(table, table->size * HASH_CAP_GROWTH_FACTOR);
336 }
337 
HashAllocate(HashTable * table,size_t capacity)338 int HashAllocate(HashTable *table, size_t capacity)
339 {
340     if (capacity == 0) {
341         return HASH_ERROR;
342     }
343     if ((table->nodes = calloc(capacity, sizeof(HashNode *))) == 0) {
344         return HASH_ERROR;
345     }
346     table->capacity = capacity;
347     table->threshold = capacity * HASH_CAP_LOAD_FACTOR;
348     return HASH_SUCCESS;
349 }
350 
Resize(HashTable * table,size_t newSize)351 int Resize(HashTable *table, size_t newSize)
352 {
353     HashNode **old;
354     size_t oldSize;
355     size_t readySize = newSize;
356     if (readySize < HASH_MINI_CAPACITY) {
357         if (table->capacity > HASH_MINI_CAPACITY) {
358             readySize = HASH_MINI_CAPACITY;
359         } else {
360             return HASH_SUCCESS;
361         }
362     }
363 
364     old = table->nodes;
365     oldSize = table->capacity;
366     if (HashAllocate(table, readySize) == HASH_ERROR) {
367         return HASH_ERROR;
368     }
369     HashRehash(table, old, oldSize);
370     free(old);
371     old = NULL;
372     return HASH_SUCCESS;
373 }
374 
HashRehash(HashTable * table,HashNode ** old,size_t oldCapacity)375 void HashRehash(HashTable *table, HashNode **old, size_t oldCapacity)
376 {
377     for (size_t current = 0; current < oldCapacity; ++current) {
378         HashNode *node = old[current];
379         while (node != 0) {
380             HashNode *next = node->next;
381             size_t newPos = Hash(table, node->key);
382             node->next = table->nodes[newPos];
383             table->nodes[newPos] = node;
384             node = next;
385         }
386     }
387 }
388