@@ -374,6 +374,9 @@ void arena_free(arena_t *arena)
374374 */
375375int hashmap_hash_index (int size , char * key )
376376{
377+ if (!key )
378+ return 0 ;
379+
377380 int hash = 0x811c9dc5 ;
378381
379382 for (; * key ; key ++ ) {
@@ -415,90 +418,61 @@ hashmap_t *hashmap_create(int cap)
415418
416419 map -> size = 0 ;
417420 map -> cap = round_up_pow2 (cap );
418- map -> buckets = calloc (map -> cap , sizeof (hashmap_node_t * ));
421+ map -> table = calloc (map -> cap , sizeof (hashmap_node_t ));
419422
420- if (!map -> buckets ) {
421- printf ("Failed to allocate buckets in hashmap_t\n" );
423+ if (!map -> table ) {
424+ printf ("Failed to allocate table in hashmap_t\n" );
422425 free (map );
423426 return NULL ;
424427 }
425428
426429 return map ;
427430}
428431
429- /* Create a hashmap node on heap.
430- * @key: The key of node. Must not be NULL.
431- * @val: The value of node. Could be NULL.
432- *
433- * Return: The pointer of created node.
434- */
435- hashmap_node_t * hashmap_node_new (char * key , void * val )
436- {
437- if (!key )
438- return NULL ;
439-
440- const int len = strlen (key );
441- hashmap_node_t * node = arena_alloc (HASHMAP_ARENA , sizeof (hashmap_node_t ));
442-
443-
444- if (!node ) {
445- printf ("Failed to allocate hashmap_node_t\n" );
446- return NULL ;
447- }
448-
449- node -> key = arena_alloc (HASHMAP_ARENA , len + 1 );
450- if (!node -> key ) {
451- printf ("Failed to allocate hashmap_node_t key with size %d\n" , len + 1 );
452- return NULL ;
453- }
454-
455- strcpy (node -> key , key );
456- node -> val = val ;
457- node -> next = NULL ;
458- return node ;
459- }
460432
461433void hashmap_rehash (hashmap_t * map )
462434{
463435 if (!map )
464436 return ;
465437
466438 int old_cap = map -> cap ;
467- hashmap_node_t * * old_buckets = map -> buckets ;
439+ hashmap_node_t * old_table = map -> table ;
468440
469441 map -> cap <<= 1 ;
470- map -> buckets = calloc (map -> cap , sizeof (hashmap_node_t * ));
442+ map -> table = calloc (map -> cap , sizeof (hashmap_node_t ));
471443
472- if (!map -> buckets ) {
473- printf ("Failed to allocate new buckets in hashmap_t\n" );
474- map -> buckets = old_buckets ;
444+ if (!map -> table ) {
445+ printf ("Failed to allocate new table in hashmap_t\n" );
446+ map -> table = old_table ;
475447 map -> cap = old_cap ;
476448 return ;
477449 }
478450
451+ map -> size = 0 ;
452+
479453 for (int i = 0 ; i < old_cap ; i ++ ) {
480- hashmap_node_t * cur = old_buckets [i ];
481- hashmap_node_t * next ;
482- hashmap_node_t * target_cur ;
483-
484- while (cur ) {
485- next = cur -> next ;
486- cur -> next = NULL ;
487- int index = hashmap_hash_index (map -> cap , cur -> key );
488- target_cur = map -> buckets [index ];
489-
490- if (!target_cur ) {
491- map -> buckets [index ] = cur ;
492- } else {
493- cur -> next = target_cur ;
494- map -> buckets [index ] = cur ;
454+ if (old_table [i ].occupied ) {
455+ char * key = old_table [i ].key ;
456+ void * val = old_table [i ].val ;
457+
458+ int index = hashmap_hash_index (map -> cap , key );
459+ int start = index ;
460+
461+ while (map -> table [index ].occupied ) {
462+ index = (index + 1 ) & (map -> cap - 1 );
463+ if (index == start ) {
464+ printf ("Error: New table is full during rehash\n" );
465+ abort ();
466+ }
495467 }
496468
497- cur = next ;
469+ map -> table [index ].key = key ;
470+ map -> table [index ].val = val ;
471+ map -> table [index ].occupied = true;
472+ map -> size ++ ;
498473 }
499474 }
500-
501- free (old_buckets );
475+ free (old_table );
502476}
503477
504478/* Put a key-value pair into given hashmap.
@@ -514,22 +488,30 @@ void hashmap_put(hashmap_t *map, char *key, void *val)
514488 if (!map )
515489 return ;
516490
491+ /* Check if size of map exceeds load factor 50% (or 1/2 of capacity) */
492+ if ((map -> cap >> 1 ) <= map -> size )
493+ hashmap_rehash (map );
494+
517495 int index = hashmap_hash_index (map -> cap , key );
518- hashmap_node_t * cur = map -> buckets [index ],
519- * new_node = hashmap_node_new (key , val );
496+ int start = index ;
520497
521- if (!cur ) {
522- map -> buckets [index ] = new_node ;
523- } else {
524- while (cur -> next )
525- cur = cur -> next ;
526- cur -> next = new_node ;
498+ while (map -> table [index ].occupied ) {
499+ if (!strcmp (map -> table [index ].key , key )) {
500+ map -> table [index ].val = val ;
501+ return ;
502+ }
503+
504+ index = (index + 1 ) & (map -> cap - 1 );
505+ if (index == start ) {
506+ printf ("Error: Hashmap is full\n" );
507+ abort ();
508+ }
527509 }
528510
511+ map -> table [index ].key = arena_strdup (HASHMAP_ARENA , key );
512+ map -> table [index ].val = val ;
513+ map -> table [index ].occupied = true;
529514 map -> size ++ ;
530- /* Check if size of map exceeds load factor 75% (or 3/4 of capacity) */
531- if ((map -> cap >> 2 ) + (map -> cap >> 1 ) <= map -> size )
532- hashmap_rehash (map );
533515}
534516
535517/* Get key-value pair node from hashmap from given key.
@@ -545,10 +527,16 @@ hashmap_node_t *hashmap_get_node(hashmap_t *map, char *key)
545527 return NULL ;
546528
547529 int index = hashmap_hash_index (map -> cap , key );
530+ int start = index ;
531+
532+ while (map -> table [index ].occupied ) {
533+ if (!strcmp (map -> table [index ].key , key ))
534+ return & map -> table [index ];
548535
549- for (hashmap_node_t * cur = map -> buckets [index ]; cur ; cur = cur -> next )
550- if (!strcmp (cur -> key , key ))
551- return cur ;
536+ index = (index + 1 ) & (map -> cap - 1 );
537+ if (index == start )
538+ return NULL ;
539+ }
552540
553541 return NULL ;
554542}
@@ -586,7 +574,7 @@ void hashmap_free(hashmap_t *map)
586574 if (!map )
587575 return ;
588576
589- free (map -> buckets );
577+ free (map -> table );
590578 free (map );
591579}
592580
0 commit comments