add generic hashmap and memory usage fix

This commit is contained in:
2025-04-30 01:38:53 +02:00
parent 97db6c54e7
commit dc39cf9d64
13 changed files with 315 additions and 161 deletions

View File

@@ -1,101 +1,137 @@
#include "utils/hashmap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cws_hm_hash(int sockfd) { return sockfd % CWS_HASHMAP_MAX_CLIENTS; }
cws_hashmap *cws_hm_init(cws_hash_fn *hash_fn, cws_equal_fn *equal_fn, cws_free_key_fn *free_key_fn, cws_free_value_fn *free_value_fn) {
/* Allocate hash map struct */
cws_hashmap *hashmap = (cws_hashmap *)malloc(sizeof(cws_hashmap));
void cws_hm_init(cws_bucket *bucket) {
/* Initialize everything to 0 for the struct, then -1 for fd and next to NULL */
memset(bucket, 0, sizeof(cws_bucket) * CWS_HASHMAP_MAX_CLIENTS);
for (size_t i = 0; i < CWS_HASHMAP_MAX_CLIENTS; ++i) {
bucket[i].sockfd = -1;
bucket[i].next = NULL;
bucket[i].prev = NULL;
}
}
void cws_hm_insert(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas) {
int index = cws_hm_hash(sockfd);
if (bucket[index].sockfd == -1) {
/* Current slot is empty */
bucket[index].sockfd = sockfd;
bucket[index].sas = *sas;
} else {
/* Append the new key to the head (not the first element because it belongs to the array) of the linked
* list */
cws_bucket *p = &bucket[index];
cws_bucket *new = malloc(sizeof(cws_bucket));
new->sockfd = sockfd;
new->sas = *sas;
new->next = p->next;
new->prev = p;
p->next = new;
}
}
cws_bucket *cws_hm_lookup(cws_bucket *bucket, int sockfd) {
int index = cws_hm_hash(sockfd);
if (bucket[index].sockfd != sockfd) {
cws_bucket *p;
for (p = bucket[index].next; p != NULL && p->sockfd != sockfd; p = p->next);
return p;
} else {
return &bucket[index];
if (hashmap == NULL) {
return NULL;
}
return NULL;
/* Populate hash map with given parameters */
hashmap->hash_fn = hash_fn;
hashmap->equal_fn = equal_fn;
hashmap->free_key_fn = free_key_fn;
hashmap->free_value_fn = free_value_fn;
/* Clear cws_bucket map */
memset(hashmap->map, 0, sizeof(hashmap->map));
return hashmap;
}
void cws_hm_push(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas) {
if (cws_hm_lookup(bucket, sockfd) == NULL) {
cws_hm_insert(bucket, sockfd, sas);
}
}
void cws_hm_remove(cws_bucket *bucket, int sockfd) {
if (cws_hm_is_in_bucket_array(bucket, sockfd)) {
/* Instead of doing this I could copy the memory of the next node into the head */
int index = cws_hm_hash(sockfd);
bucket[index].sockfd = -1;
void cws_hm_free(cws_hashmap *hashmap) {
if (hashmap == NULL) {
return;
}
/* Key not in the bucket array, let's search in the linked list */
cws_bucket *p = cws_hm_lookup(bucket, sockfd);
if (p == NULL) return;
p->prev->next = p->next;
if (p->next != NULL) {
/* If there's a next node update the previous node */
p->next->prev = p->prev;
}
free(p);
}
for (size_t i = 0; i < CWS_HASHMAP_SIZE; ++i) {
cws_bucket *bucket = &hashmap->map[i];
if (bucket->key != NULL) {
if (hashmap->free_key_fn != NULL) {
hashmap->free_key_fn(bucket->key);
}
if (hashmap->free_value_fn != NULL) {
hashmap->free_value_fn(bucket->value);
}
}
void cws_hm_free(cws_bucket *bucket) {
cws_bucket *p, *next;
for (size_t i = 0; i < CWS_HASHMAP_MAX_CLIENTS; ++i) {
if (bucket[i].next != NULL) {
/* Free the malloc */
p = bucket[i].next;
next = p->next;
do {
free(p);
p = next;
next = p != NULL ? p->next : NULL;
} while (p != NULL);
bucket = bucket->next;
while (bucket) {
if (hashmap->free_key_fn != NULL) {
hashmap->free_key_fn(bucket->key);
}
if (hashmap->free_value_fn != NULL) {
hashmap->free_value_fn(bucket->value);
}
cws_bucket *next = bucket->next;
free(bucket);
bucket = next;
}
}
free(hashmap);
}
bool cws_hm_is_in_bucket_array(cws_bucket *bucket, int sockfd) {
int index = cws_hm_hash(sockfd);
if (bucket[index].sockfd == sockfd) return true;
bool cws_hm_set(cws_hashmap *hashmap, void *key, void *value) {
/* Get hash index */
int index = hashmap->hash_fn(key);
cws_bucket *bucket = &hashmap->map[index];
return false;
/* Check if the key at index is empty */
if (bucket->key == NULL) {
/* Bucket is empty */
/* Set the key and value */
bucket->key = key;
bucket->value = value;
bucket->next = NULL;
return true;
}
/* Check if bucket is already set */
if (hashmap->equal_fn(bucket->key, key)) {
/* Same key, free value and update it */
if (hashmap->free_value_fn != NULL) {
hashmap->free_value_fn(bucket->value);
}
bucket->value = value;
return true;
}
/* Key not found, iterate through the linked list */
cws_bucket *next = bucket->next;
while (next) {
if (hashmap->equal_fn(next->key, key)) {
/* Same key, free value and update it */
if (hashmap->free_value_fn != NULL) {
hashmap->free_value_fn(next->value);
}
next->value = value;
return true;
}
next = next->next;
}
/* Append the new key/value to the head of the linked list */
next = (cws_bucket *)malloc(sizeof(cws_bucket));
if (next == NULL) {
return false;
}
next->key = key;
next->value = value;
next->next = bucket->next;
bucket->next = next;
return true;
}
cws_bucket *cws_hm_get(cws_hashmap *hashmap, void *key) {
/* Return if key is null */
if (key == NULL) {
return NULL;
}
int index = hashmap->hash_fn(key);
cws_bucket *bucket = &hashmap->map[index];
/* Key is not in the hash map */
if (bucket == NULL || bucket->key == NULL) {
return NULL;
}
/* Iterate through the linked list */
while (bucket) {
if (hashmap->equal_fn(bucket->key, key)) {
return bucket;
}
bucket = bucket->next;
}
/* Key not found */
return NULL;
}

View File

@@ -43,4 +43,27 @@ void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
inet_ntop(AF_INET, &sin->sin_addr, ip, INET_ADDRSTRLEN);
}
}
int my_hash_fn(void *key) {
char *key_str = (char *)key;
size_t key_len = strlen(key_str);
int total = 0;
for (size_t i = 0; i < key_len; ++i) {
total += (int)key_str[i];
}
return total % 2069;
}
bool my_equal_fn(void *a, void *b) {
if (strcmp((char *)a, (char *)b) == 0) {
return true;
}
return false;
}
void my_free_str_fn(void *value) { free(value); }