Skip to content

Commit 4924f83

Browse files
committed
Overhaul hashmap_t functionalities
This patch fixes constracts of hashmap_t-related function, including: - hashmap_contains: Instead of delegates to result returned by hashmap_get, now shares similar logic to avoid bucket node value being NULL and treat as false. - hashmap_free: Now respects bucket node value's pointer, if it's already NULL, then hashmap won't free it. Additionally, now hashmap_t is capable of rehashing its underlying bucket node array when load factor reaches 75%. Close #190.
1 parent 61c9d10 commit 4924f83

File tree

2 files changed

+90
-32
lines changed

2 files changed

+90
-32
lines changed

src/defs.h

+14-13
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ typedef struct {
7878
arena_block_t *head;
7979
} arena_t;
8080

81+
/* string-based hash map definitions */
82+
83+
typedef struct hashmap_node {
84+
char *key;
85+
void *val;
86+
struct hashmap_node *next;
87+
} hashmap_node_t;
88+
89+
typedef struct {
90+
int size;
91+
int cap;
92+
hashmap_node_t **buckets;
93+
} hashmap_t;
94+
8195
/* builtin types */
8296
typedef enum {
8397
TYPE_void = 0,
@@ -331,19 +345,6 @@ typedef struct {
331345
int value;
332346
} constant_t;
333347

334-
/* string-based hash map definitions */
335-
336-
typedef struct hashmap_node {
337-
char *key;
338-
void *val;
339-
struct hashmap_node *next;
340-
} hashmap_node_t;
341-
342-
typedef struct {
343-
int size;
344-
hashmap_node_t **buckets;
345-
} hashmap_t;
346-
347348
struct phi_operand {
348349
var_t *var;
349350
basic_block_t *from;

src/globals.c

+76-19
Original file line numberDiff line numberDiff line change
@@ -231,27 +231,25 @@ int round_up_pow2(int v)
231231
*
232232
* Return: The pointer of created hashmap.
233233
*/
234-
hashmap_t *hashmap_create(int size)
234+
hashmap_t *hashmap_create(int cap)
235235
{
236236
hashmap_t *map = malloc(sizeof(hashmap_t));
237237

238238
if (!map) {
239-
printf("Failed to allocate hashmap_t with size %d\n", size);
239+
printf("Failed to allocate hashmap_t with capacity %d\n", cap);
240240
return NULL;
241241
}
242242

243-
map->size = round_up_pow2(size);
244-
map->buckets = malloc(map->size * sizeof(hashmap_node_t *));
243+
map->size = 0;
244+
map->cap = round_up_pow2(cap);
245+
map->buckets = calloc(map->cap, sizeof(hashmap_node_t *));
245246

246247
if (!map->buckets) {
247248
printf("Failed to allocate buckets in hashmap_t\n");
248249
free(map);
249250
return NULL;
250251
}
251252

252-
for (int i = 0; i < map->size; i++)
253-
map->buckets[i] = 0;
254-
255253
return map;
256254
}
257255

@@ -290,6 +288,47 @@ hashmap_node_t *hashmap_node_new(char *key, void *val)
290288
return node;
291289
}
292290

291+
void hashmap_rehash(hashmap_t *map)
292+
{
293+
if (!map)
294+
return;
295+
296+
int old_cap = map->cap;
297+
hashmap_node_t **old_buckets = map->buckets;
298+
299+
map->cap *= 2;
300+
map->buckets = calloc(map->cap, sizeof(hashmap_node_t *));
301+
302+
if (!map->buckets) {
303+
printf("Failed to allocate new buckets in hashmap_t\n");
304+
map->buckets = old_buckets;
305+
map->cap = old_cap;
306+
return;
307+
}
308+
309+
for (int i = 0; i < old_cap; i++) {
310+
hashmap_node_t *cur = old_buckets[i], *next, *target_cur;
311+
312+
while (cur) {
313+
next = cur->next;
314+
cur->next = NULL;
315+
int index = hashmap_hash_index(map->cap, cur->key);
316+
target_cur = map->buckets[index];
317+
318+
if (!target_cur) {
319+
map->buckets[index] = cur;
320+
} else {
321+
cur->next = target_cur;
322+
map->buckets[index] = cur;
323+
}
324+
325+
cur = next;
326+
}
327+
}
328+
329+
free(old_buckets);
330+
}
331+
293332
/**
294333
* hashmap_put() - puts a key-value pair into given hashmap.
295334
* If key already contains a value, then replace it with new
@@ -304,42 +343,59 @@ void hashmap_put(hashmap_t *map, char *key, void *val)
304343
if (!map)
305344
return;
306345

307-
int index = hashmap_hash_index(map->size, key);
308-
hashmap_node_t *cur = map->buckets[index];
346+
int index = hashmap_hash_index(map->cap, key);
347+
hashmap_node_t *cur = map->buckets[index],
348+
*new_node = hashmap_node_new(key, val);
309349

310350
if (!cur) {
311-
map->buckets[index] = hashmap_node_new(key, val);
351+
map->buckets[index] = new_node;
312352
} else {
313353
while (cur->next)
314354
cur = cur->next;
315-
cur->next = hashmap_node_new(key, val);
355+
cur->next = new_node;
316356
}
317357

318-
/* TODO: Rehash if size exceeds size * load factor */
358+
map->size++;
359+
if ((map->cap >> 2) * 3 <= map->size)
360+
hashmap_rehash(map);
319361
}
320362

321363
/**
322-
* hashmap_get() - gets value from hashmap from given key.
364+
* hashmap_get_node() - gets key-value pair node from hashmap from given key.
323365
* @map: The hashmap to be looked up. Must no be NULL.
324366
* @key: The key string. May be NULL.
325367
*
326368
* Return: The look up result, if the key-value pair entry
327-
* exists, then returns its value's address, NULL otherwise.
369+
* exists, then returns address of itself, NULL otherwise.
328370
*/
329-
void *hashmap_get(hashmap_t *map, char *key)
371+
hashmap_node_t *hashmap_get_node(hashmap_t *map, char *key)
330372
{
331373
if (!map)
332374
return NULL;
333375

334-
int index = hashmap_hash_index(map->size, key);
376+
int index = hashmap_hash_index(map->cap, key);
335377

336378
for (hashmap_node_t *cur = map->buckets[index]; cur; cur = cur->next)
337379
if (!strcmp(cur->key, key))
338-
return cur->val;
380+
return cur;
339381

340382
return NULL;
341383
}
342384

385+
/**
386+
* hashmap_get() - gets value from hashmap from given key.
387+
* @map: The hashmap to be looked up. Must no be NULL.
388+
* @key: The key string. May be NULL.
389+
*
390+
* Return: The look up result, if the key-value pair entry
391+
* exists, then returns its value's address, NULL otherwise.
392+
*/
393+
void *hashmap_get(hashmap_t *map, char *key)
394+
{
395+
hashmap_node_t *node = hashmap_get_node(map, key);
396+
return node ? node->val : NULL;
397+
}
398+
343399
/**
344400
* hashmap_contains() - checks if the key-value pair entry exists
345401
* from given key.
@@ -351,7 +407,7 @@ void *hashmap_get(hashmap_t *map, char *key)
351407
*/
352408
bool hashmap_contains(hashmap_t *map, char *key)
353409
{
354-
return hashmap_get(map, key);
410+
return hashmap_get_node(map, key);
355411
}
356412

357413
/**
@@ -368,7 +424,8 @@ void hashmap_free(hashmap_t *map)
368424
for (hashmap_node_t *cur = map->buckets[i], *next; cur; cur = next) {
369425
next = cur->next;
370426
free(cur->key);
371-
free(cur->val);
427+
if (cur->val)
428+
free(cur->val);
372429
free(cur);
373430
cur = next;
374431
}

0 commit comments

Comments
 (0)