From 9db7d84a67c2fe1c811989e3e1a616242d1bdec0 Mon Sep 17 00:00:00 2001
From: Orestis <orestis.malaspinas@pm.me>
Date: Fri, 14 Jan 2022 23:10:15 +0100
Subject: [PATCH] added hashmap example for live code

---
 examples/hashmap/.gitignore |   2 +
 examples/hashmap/Makefile   |  24 +++++++
 examples/hashmap/hm.c       | 123 ++++++++++++++++++++++++++++++++++++
 examples/hashmap/hm.h       |  30 +++++++++
 examples/hashmap/main.c     |  21 ++++++
 5 files changed, 200 insertions(+)
 create mode 100644 examples/hashmap/.gitignore
 create mode 100644 examples/hashmap/Makefile
 create mode 100644 examples/hashmap/hm.c
 create mode 100644 examples/hashmap/hm.h
 create mode 100644 examples/hashmap/main.c

diff --git a/examples/hashmap/.gitignore b/examples/hashmap/.gitignore
new file mode 100644
index 0000000..87e54c2
--- /dev/null
+++ b/examples/hashmap/.gitignore
@@ -0,0 +1,2 @@
+main
+*.o
diff --git a/examples/hashmap/Makefile b/examples/hashmap/Makefile
new file mode 100644
index 0000000..604c269
--- /dev/null
+++ b/examples/hashmap/Makefile
@@ -0,0 +1,24 @@
+CC=gcc
+CFLAGS=-g -std=gnu11 -Wall -Wextra -pedantic -fsanitize=address -fsanitize=leak -fsanitize=undefined
+LDFLAGS=-fsanitize=address -fsanitize=leak -fsanitize=undefined
+SOURCES=$(wildcard *.c)
+OBJECTS=$(SOURCES:.c=.o)
+
+TARGET = main
+
+all: $(TARGET) 
+
+exec_tests:
+	make -C tests/ exec_tests
+
+$(TARGET): $(OBJECTS) 
+	$(CC) $^ -o $@ $(LDFLAGS)
+
+hashmap.c: hashmap.h
+
+.PHONY = clean tests
+
+clean:
+	rm -f $(OBJECTS) $(TARGET) 
+	make clean -C tests
+
diff --git a/examples/hashmap/hm.c b/examples/hashmap/hm.c
new file mode 100644
index 0000000..97c1303
--- /dev/null
+++ b/examples/hashmap/hm.c
@@ -0,0 +1,123 @@
+#include "hm.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static bool is_not_allocated(hm h) {
+    return (h.table == NULL || h.capacity < 1 || h.size < 0);
+}
+
+static size_t hash(hm h, char key[MAX_LEN]) {
+    int index = 0;
+    for (size_t i = 0; i < strlen(key); ++i) {
+        index = (index + key[i] * 43) % h.capacity;
+    }
+    return index;
+}
+
+static int rehash(char *key) {
+    return 1;
+}
+
+static int find_index(hm h, char key[MAX_LEN], bool insert) {
+    int try   = 0;
+    int index = hash(h, key);
+    while (try < h.capacity) {
+        switch (h.table[index].state) {
+            case occupied:
+                if (strncmp(h.table[index].key, key, MAX_LEN) == 0) {
+                    return index;
+                }
+                break;
+            case empty:
+                return index;
+                break;
+            case deleted:
+                if (insert) {
+                    return index;
+                }
+                break;
+            default:
+                return -1;
+                break;
+        }
+        index = (index + rehash(key)) % h.capacity;
+        try += 1;
+    }
+    return -1;
+}
+
+static bool is_empty(hm h) {
+    return h.size == 0;
+}
+
+void hm_init(hm *h, int capacity) {
+    h->capacity = capacity;
+    h->size     = 0;
+    h->table    = malloc(h->capacity * sizeof(*h->table));
+    for (int i = 0; i < h->capacity; ++i) {
+        h->table[i].state = empty;
+    }
+}
+
+void hm_destroy(hm *h) {
+    h->capacity = -1;
+    h->size     = -1;
+    free(h->table);
+    h->table = NULL;
+}
+
+bool hm_set(hm *h, char *key, char *value) {
+    if (is_not_allocated(*h)) {
+        return false;
+    }
+
+    int index = find_index(*h, key, true);
+    if (index < 0) {
+        return false;
+    }
+    /* printf("%d\n", index); */
+    strncpy(h->table[index].value, value, MAX_LEN);
+    strncpy(h->table[index].key, key, MAX_LEN);
+    h->table[index].state = occupied;
+    h->size += 1;
+    return true;
+}
+
+bool hm_get(hm h, char *key, char *value) {
+    int index = find_index(h, key, false);
+    if (index >= 0 && h.table[index].state == occupied) {
+        strncpy(value, h.table[index].value, MAX_LEN);
+        return true;
+    }
+    return false;
+}
+bool hm_remove(hm *h, char *key, char *value) {
+    int index = find_index(*h, key, false);
+    if (index >= 0 && h->table[index].state == occupied) {
+        h->table[index].state = deleted;
+        strncpy(value, h->table[index].value, MAX_LEN);
+        h->size -= 1;
+        return true;
+    }
+    return false;
+}
+
+bool hm_search(hm h, char *key) {
+    int index = find_index(h, key, false);
+    return (index >= 0 && h.table[index].state == occupied);
+}
+
+void hm_print(hm h) {
+    if (is_not_allocated(h)) {
+        printf("Well this hashmap is not allocated n00b.\n");
+    }
+    if (is_empty(h)) {
+        printf("The hashmap is empty.\n");
+    }
+    for (int i = 0; i < h.capacity; ++i) {
+        printf("index: %d, key: %s, value: %s\n", i, h.table[i].key,
+            h.table[i].value);
+    }
+}
+
diff --git a/examples/hashmap/hm.h b/examples/hashmap/hm.h
new file mode 100644
index 0000000..7572fd8
--- /dev/null
+++ b/examples/hashmap/hm.h
@@ -0,0 +1,30 @@
+#ifndef _HM_H_
+#define _HM_H_
+
+#include <stdbool.h>
+
+#define MAX_LEN 80
+
+typedef enum { empty, occupied, deleted } state_t;
+
+typedef struct _cell_t {
+    char key[MAX_LEN];
+    char value[MAX_LEN];
+    state_t state;
+} cell_t;
+
+typedef struct _hm {
+    cell_t *table;
+    int capacity;
+    int size;
+} hm;
+
+void hm_init(hm *h, int capacity);
+void hm_destroy(hm *h);
+bool hm_set(hm *h, char *key, char *value);
+bool hm_get(hm h, char *key, char *value);
+bool hm_remove(hm *h, char *key, char *value);
+bool hm_search(hm h, char *key);
+void hm_print(hm h);
+
+#endif
diff --git a/examples/hashmap/main.c b/examples/hashmap/main.c
new file mode 100644
index 0000000..b8f5927
--- /dev/null
+++ b/examples/hashmap/main.c
@@ -0,0 +1,21 @@
+#include "hm.h"
+#include <stdio.h>
+
+int main() {
+    char key[80], value[80];
+    hm h;
+    hm_init(&h, 5);
+    for (int i = 0; i < 6; ++i) {
+        scanf("%s", key);
+        scanf("%s", value);
+        hm_set(&h, key, value);
+        hm_print(h);
+        if (hm_search(h, "orestis")) {
+            printf("orestis found.\n");
+        }
+        if (hm_remove(&h, "orestis", value)) {
+            printf("orestis removed: %s.\n", value);
+        }
+    }
+    hm_destroy(&h);
+}
-- 
GitLab