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