@@ -414,90 +414,64 @@ hashmap_t *hashmap_create(int cap)
414
414
415
415
map -> size = 0 ;
416
416
map -> cap = round_up_pow2 (cap );
417
- map -> buckets = calloc (map -> cap , sizeof (hashmap_node_t * ));
417
+ map -> table = calloc (map -> cap , sizeof (hashmap_node_t ));
418
418
419
- if (!map -> buckets ) {
420
- printf ("Failed to allocate buckets in hashmap_t\n" );
419
+ if (!map -> table ) {
420
+ printf ("Failed to allocate table in hashmap_t\n" );
421
421
free (map );
422
422
return NULL ;
423
423
}
424
424
425
425
return map ;
426
426
}
427
427
428
- /* Create a hashmap node on heap.
429
- * @key: The key of node. Must not be NULL.
430
- * @val: The value of node. Could be NULL.
431
- *
432
- * Return: The pointer of created node.
433
- */
434
- hashmap_node_t * hashmap_node_new (char * key , void * val )
435
- {
436
- if (!key )
437
- return NULL ;
438
-
439
- const int len = strlen (key );
440
- hashmap_node_t * node = arena_alloc (HASHMAP_ARENA , sizeof (hashmap_node_t ));
441
-
442
-
443
- if (!node ) {
444
- printf ("Failed to allocate hashmap_node_t\n" );
445
- return NULL ;
446
- }
447
-
448
- node -> key = arena_alloc (HASHMAP_ARENA , len + 1 );
449
- if (!node -> key ) {
450
- printf ("Failed to allocate hashmap_node_t key with size %d\n" , len + 1 );
451
- return NULL ;
452
- }
453
-
454
- strcpy (node -> key , key );
455
- node -> val = val ;
456
- node -> next = NULL ;
457
- return node ;
458
- }
459
428
460
429
void hashmap_rehash (hashmap_t * map )
461
430
{
462
431
if (!map )
463
432
return ;
464
433
465
434
int old_cap = map -> cap ;
466
- hashmap_node_t * * old_buckets = map -> buckets ;
435
+ hashmap_node_t * old_table = map -> table ;
467
436
468
437
map -> cap <<= 1 ;
469
- map -> buckets = calloc (map -> cap , sizeof (hashmap_node_t * ));
438
+ map -> table = calloc (map -> cap , sizeof (hashmap_node_t ));
470
439
471
- if (!map -> buckets ) {
472
- printf ("Failed to allocate new buckets in hashmap_t\n" );
473
- map -> buckets = old_buckets ;
440
+ if (!map -> table ) {
441
+ printf ("Failed to allocate new table in hashmap_t\n" );
442
+ map -> table = old_table ;
474
443
map -> cap = old_cap ;
475
444
return ;
476
445
}
477
446
447
+ for (int i = 0 ; i < map -> cap ; i ++ )
448
+ map -> table [i ].state = 0 ;
449
+
450
+ map -> size = 0 ;
451
+
478
452
for (int i = 0 ; i < old_cap ; i ++ ) {
479
- hashmap_node_t * cur = old_buckets [i ];
480
- hashmap_node_t * next ;
481
- hashmap_node_t * target_cur ;
482
-
483
- while (cur ) {
484
- next = cur -> next ;
485
- cur -> next = NULL ;
486
- int index = hashmap_hash_index (map -> cap , cur -> key );
487
- target_cur = map -> buckets [index ];
488
-
489
- if (!target_cur ) {
490
- map -> buckets [index ] = cur ;
491
- } else {
492
- cur -> next = target_cur ;
493
- map -> buckets [index ] = cur ;
453
+ if (old_table [i ].state == 1 ) {
454
+ char * key = old_table [i ].key ;
455
+ void * val = old_table [i ].val ;
456
+
457
+ int index = hashmap_hash_index (map -> cap , key );
458
+ int start = index ;
459
+
460
+ while (map -> table [index ].state == 1 ) {
461
+ index = (index + 1 ) & (map -> cap - 1 );
462
+ if (index == start ) {
463
+ printf ("Error: New table is full during rehash\n" );
464
+ abort ();
465
+ }
494
466
}
495
467
496
- cur = next ;
468
+ map -> table [index ].key = key ;
469
+ map -> table [index ].val = val ;
470
+ map -> table [index ].state = 1 ;
471
+ map -> size ++ ;
497
472
}
498
473
}
499
-
500
- free (old_buckets );
474
+ free (old_table );
501
475
}
502
476
503
477
/* Put a key-value pair into given hashmap.
@@ -513,22 +487,28 @@ void hashmap_put(hashmap_t *map, char *key, void *val)
513
487
if (!map )
514
488
return ;
515
489
490
+ /* Check if size of map exceeds load factor 50% (or 1/2 of capacity) */
491
+ if ((map -> cap >> 1 ) <= map -> size )
492
+ hashmap_rehash (map );
493
+
516
494
int index = hashmap_hash_index (map -> cap , key );
517
- hashmap_node_t * cur = map -> buckets [index ],
518
- * new_node = hashmap_node_new (key , val );
495
+ int start = index ;
519
496
520
- if (!cur ) {
521
- map -> buckets [index ] = new_node ;
522
- } else {
523
- while (cur -> next )
524
- cur = cur -> next ;
525
- cur -> next = new_node ;
497
+ while (map -> table [index ].state == 1 ) {
498
+ if (strcmp (map -> table [index ].key , key ) == 0 ) {
499
+ map -> table [index ].val = val ;
500
+ return ;
501
+ }
502
+
503
+ index = (index + 1 ) & (map -> cap - 1 );
504
+ if (index == start )
505
+ return ;
526
506
}
527
507
508
+ map -> table [index ].key = arena_strdup (HASHMAP_ARENA , key );
509
+ map -> table [index ].val = val ;
510
+ map -> table [index ].state = 1 ;
528
511
map -> size ++ ;
529
- /* Check if size of map exceeds load factor 75% (or 3/4 of capacity) */
530
- if ((map -> cap >> 2 ) + (map -> cap >> 1 ) <= map -> size )
531
- hashmap_rehash (map );
532
512
}
533
513
534
514
/* Get key-value pair node from hashmap from given key.
@@ -544,10 +524,16 @@ hashmap_node_t *hashmap_get_node(hashmap_t *map, char *key)
544
524
return NULL ;
545
525
546
526
int index = hashmap_hash_index (map -> cap , key );
527
+ int start = index ;
547
528
548
- for (hashmap_node_t * cur = map -> buckets [index ]; cur ; cur = cur -> next )
549
- if (!strcmp (cur -> key , key ))
550
- return cur ;
529
+ while (map -> table [index ].state == 1 ) {
530
+ if (strcmp (map -> table [index ].key , key ) == 0 )
531
+ return & map -> table [index ];
532
+
533
+ index = (index + 1 ) & (map -> cap - 1 );
534
+ if (index == start )
535
+ return NULL ;
536
+ }
551
537
552
538
return NULL ;
553
539
}
@@ -574,7 +560,7 @@ void *hashmap_get(hashmap_t *map, char *key)
574
560
*/
575
561
bool hashmap_contains (hashmap_t * map , char * key )
576
562
{
577
- return hashmap_get_node (map , key );
563
+ return hashmap_get_node (map , key ) != NULL ;
578
564
}
579
565
580
566
/* Free the hashmap, this also frees key-value pair entry's value.
@@ -585,7 +571,7 @@ void hashmap_free(hashmap_t *map)
585
571
if (!map )
586
572
return ;
587
573
588
- free (map -> buckets );
574
+ free (map -> table );
589
575
free (map );
590
576
}
591
577
0 commit comments