G

G Programming Language
git clone http://git.omkov.net/G
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2021-12-08 06:46:24
Commit0955f0975240413d08f5e09eea918e3a40219f3a
Parent954d27a5abbf25a73a0df3b21660239ae9a1c9d2

util: Add experimental generic hashmap

Diffstat

D src/map.c | 62 --------------------------------------------------------------
D src/map.h | 28 ----------------------------
A src/util/map.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A src/util/map.h | 28 ++++++++++++++++++++++++++++

4 files changed, 143 insertions, 90 deletions

diff --git a/src/map.c b/src/map.c
deleted file mode 100644
index fa2e39e..0000000
--- a/src/map.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// map.c
-// Map source file for G
-// Copyright (C) 2021, Jakob Wakeling
-// All rights reserved.
-
-
-
-#include "map.h"
-#include "util/error.h"
-#include "util/fnv.h"
-#include "util/util.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/* Grow a map. */
-static inline void map_grow(map *m) {
-	/* TODO */
-}
-
-/* Re-hash a map. */
-static inline void map_hash(map *m) {
-	/* TODO */
-}
-
-/* Initialise a map. */
-void map_init(map *m) {
-	m->al = 0; m->ac = 1024;
-	m->a = calloc(m->ac, sizeof (ent *));
-}
-
-/* Free a map. */
-void map_free(map *m) {
-	/* TODO */
-}
-
-/* Insert an element into a map. */
-void map_insert(map *m, char *k, sym v) {
-	if ((f64)m->al / m->ac >= 0.75) { /* TODO */ warn("map_insert growth"); }
-	
-	u64 i = fnv1a64(k, strlen(k)) % m->ac;
-	
-	register ent *e = calloc(1, sizeof (*e)); /* TODO check memory allocation */
-	e->k = strdup(k); e->v = v; e->n = m->a[i]; m->a[i] = e;
-}
-
-/* Lookup an element in a map. */
-sym *map_lookup(map *m, char *k) {
-	u64 i = fnv1a64(k, strlen(k)) % m->ac;
-	
-	for (register ent *e = m->a[i]; e; e = e->n) {
-		if (!strcmp(k, e->k)) { return &e->v; }
-	}
-	
-	return NULL;
-}
-
-/* Pop an element from a map. */
-void map_pop(map *m, char *k) {
-	u64 i = fnv1a64(k, strlen(k)) % m->ac;
-	m->a[i] = m->a[i]->n; /* TODO deallocate memory */
-}
diff --git a/src/map.h b/src/map.h
deleted file mode 100644
index 1cdbe77..0000000
--- a/src/map.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// map.h
-// Map header file for G
-// Copyright (C) 2021, Jakob Wakeling
-// All rights reserved.
-
-
-
-#ifndef G_MAP_H_ISL5XLWM
-#define G_MAP_H_ISL5XLWM
-
-#include "util/util.h"
-#include "type.h"
-
-typedef enum { SK_VOID, } sym_k; /* Symbol Kind */
-typedef enum { SF_VOID = BIT(0), } sym_f; /* Symbol Flag */
-
-typedef struct sym { sym_k k; sym_f f; type t; } sym;
-typedef struct ent { char *k; sym v; struct ent *n, *c; } ent;
-typedef struct { ent **a, *c; UINT al, ac; } map;
-
-extern void map_init(map *m);
-extern void map_free(map *m);
-
-extern void map_insert(map *m, char *k, sym s);
-extern sym *map_lookup(map *m, char *k);
-extern void map_pop(map *m, char *k);
-
-#endif // G_MAP_H_ISL5XLWM
diff --git a/src/util/map.c b/src/util/map.c
new file mode 100644
index 0000000..901346a
--- /dev/null
+++ b/src/util/map.c
@@ -0,0 +1,115 @@
+// util/map.c, version 0.0.0
+// Map utility source file from libutil
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#include "alloc.h"
+#include "fnv.h"
+#include "map.h"
+#include "util.h"
+
+#include <malloc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOAD_FACTOR 0.75
+
+static void map_resize(map *m);
+
+/* Initialise a map. */
+map map_init(UINT el, void (*free)(void *)) {
+	return (map){ NULL, NULL, 0, 0, el, free };
+}
+
+/* Unititialise a map. */
+void map_free(map *m) {
+	for (map_ent *e = m->n, *n; e; e = n) {
+		n = e->n; if (m->free) { m->free(e->v); } free(e);
+	}
+	
+	free(m->a);
+}
+
+/* Insert a pointer into a map. */
+void *map_insert(map *m, const char *k, void *v) {
+	if (m->ac == 0 || m->al >= ((f64)m->ac * LOAD_FACTOR)) { map_resize(m); }
+	UINT index = fnv1a64(k, strlen(k)) % m->ac; void *old = map_remove(m, k);
+	
+	/* Allocate and define the entry */
+	map_ent *e = xcalloc(1, sizeof (*e));
+	// map_debug(m);
+	e->k = (char *)k; e->v = v; e->n = m->n; m->n = e;
+	
+	/* Insert the entry at begining of the buckets chain */
+	// printf("m->a: %p\n", m->a);
+	// printf("%zu\n", malloc_usable_size(m->a + (index * m->el)));
+	memcpy(&e->c, m->a + (index * m->el), m->el);
+	memcpy(m->a + (index * m->el), &e, m->el); m->al += 1;
+	
+	return old;
+}
+
+/* Lookup a pointer from a map. */
+void *map_lookup(map *m, const char *k) {
+	UINT index = fnv1a64(k, strlen(k)) % m->ac;
+	
+	map_ent *e; memcpy(&e, m->a + (index * m->el), m->el);
+	for (; e; e = e->c) { if (!strcmp(e->k, k)) { return e->v; } }
+	
+	return NULL;
+}
+
+/* Remove a pointer from the top of a map. */
+void *map_remove(map *m, const char *k) {
+	return NULL; /* TODO */
+}
+
+/* Print a basic representation of the map to stdout. */
+void map_print(map *m) {
+	for (map_ent *e = m->n; e; e = e->n) {
+		printf("%s -> %s\n", e->k, (char *)e->v);
+	}
+}
+
+/* Print a debug representation of the map to stdout. */
+/* FIXME for some reason printf leaves junk in my calloc (m->a[33]) */
+void map_debug(map *m) {
+	for (UINT i = 0; i != m->ac; i += 1) {
+		map_ent *e; memcpy(&e, m->a + (i * m->el), m->el);
+		
+		// printf("%zu: ", i);
+		for (; e; e = e->c) { printf("%s -> %s, ", e->k, (char *)e->v); }
+		// printf("\n");
+	} printf("\n");
+}
+
+/* Double the number of buckets in a map. */
+static void map_resize(map *m) {
+	if (m->ac == 0) { m->ac = 256; } else { m->ac *= 2; }
+	
+	/* If the map is empty, simply resize it without rehashing */
+	if (m->al == 0) {
+		// printf("%zu * %zu = %zu; %zu\n", m->ac, m->el, m->ac * m->el, m->ac * 8 * m->el); fflush(stdout);
+		free(m->a); m->a = xcalloc(m->ac * 8, m->el);
+		// printf("m->a: %p\n", m->a);
+		// printf("%p: %zu\n", m->a, malloc_usable_size(m->a));
+		// printf("%p: %zu\n", m->a + 1696, malloc_usable_size(m->a + 1696));
+		// printf("%zu\n", ((m->a + 1696) - m->a));
+		fflush(stdout);
+	}
+	/* Otherwise rehash every element into a new resized map */
+	else {
+		// printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); fflush(stdout);
+		
+		map old = *m;
+		
+		m->a = xcalloc(m->ac * 8, m->el); m->n = NULL; m->al = 0;
+		for (map_ent *e = old.n; e; e = e->n) { map_insert(m, e->k, e->v); }
+		
+		map_free(&old);
+	}
+}
diff --git a/src/util/map.h b/src/util/map.h
new file mode 100644
index 0000000..d4b4401
--- /dev/null
+++ b/src/util/map.h
@@ -0,0 +1,28 @@
+// util/map.h, version 0.0.0
+// Map utility header file from libutil
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#ifndef UTIL_SYMBOL_H_87BJYLNZ
+#define UTIL_SYMBOL_H_87BJYLNZ
+
+#include "util.h"
+
+#define MAP_INSERT(m, k, v) map_insert(m, k, (void *)(UINT)(e))
+
+typedef struct map_ent { char *k; void *v; struct map_ent *c, *n; } map_ent;
+typedef struct { map_ent **a, *n; UINT al, ac, el; void (*free)(void *); } map;
+
+extern map  map_init(UINT el, void (*free)(void *));
+extern void map_free(map *m);
+
+extern void *map_insert(map *m, const char *k, void *v);
+extern void *map_lookup(map *m, const char *k);
+extern void *map_remove(map *m, const char *k);
+
+extern void map_print(map *m);
+extern void map_debug(map *m);
+
+#endif // UTIL_SYMBOL_H_87BJYLNZ