summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--dynarr.h32
-rw-r--r--ihash.h109
-rw-r--r--shash.h5
-rw-r--r--stdwrm.h6
-rw-r--r--str.h41
-rw-r--r--strio.h17
-rw-r--r--typ.h33
-rw-r--r--zone.h291
8 files changed, 506 insertions, 28 deletions
diff --git a/dynarr.h b/dynarr.h
index 986c6ab..bbdd45f 100644
--- a/dynarr.h
+++ b/dynarr.h
@@ -4,9 +4,6 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
-#include <err.h>
-
-#include "stdwrm.h"
 
 typedef struct { size_t count, capacity; } DynArrHeader;
 
@@ -14,40 +11,43 @@ typedef struct { size_t count, capacity; } DynArrHeader;
 #define DA_HEADER(da) ((DynArrHeader*)(da) - 1)
 
 #define DA_INIT_CAP 16
-#define DA_INIT(da) {\
-	char *da_init_ptr = ((char*)malloc(sizeof(DynArrHeader) + DA_INIT_CAP * sizeof(*da)));\
-	if (!da_init_ptr) err(1, "dynamic array allocation failed");\
+#define DA_INIT_SZ(da, cap) do {\
+	char *da_init_ptr = ((char*)malloc(sizeof(DynArrHeader) + cap * sizeof(*da)));\
+	if (!da_init_ptr) { fprintf(stderr, "dynamic array allocation failed\n"); abort(); }\
 	da = (void *)(da_init_ptr + sizeof(DynArrHeader));\
-	*DA_HEADER(da) = (DynArrHeader) { 0, DA_INIT_CAP };\
-}
+	*DA_HEADER(da) = (DynArrHeader) { 0, cap };\
+} while(0)
+
+#define DA_INIT(da) DA_INIT_SZ(da, DA_INIT_CAP)
 
 #define DA_FREE(da)\
 	free(DA_HEADER(da))
 
 #define DA_LEN(da) (DA_HEADER(da)->count)
-#define DA_FIT(da, count)\
+#define DA_FIT(da, count) do {\
 	if (count >= DA_HEADER(da)->capacity) {\
 		while (count >= DA_HEADER(da)->capacity) DA_HEADER(da)->capacity <<= 1;\
 		char *da_fit_ptr = realloc(DA_HEADER(da), sizeof(DynArrHeader) + DA_HEADER(da)->capacity * sizeof(*da));\
-		if (!da_fit_ptr) err(1, "dynamic array reallocation failed");\
+		if (!da_fit_ptr) { fprintf(stderr, "dynamic array reallocation failed\n"); abort(); }\
 		(da) = (void *)(da_fit_ptr + sizeof(DynArrHeader));\
-	}
+	}\
+} while(0)
 
-#define DA_PUSH(da, ...) {\
+#define DA_PUSH(da, ...) do {\
 	DA_FIT(da, DA_LEN(da) + 1);\
 	(da)[DA_HEADER(da)->count++] = (__VA_ARGS__);\
-}
+} while(0)
 
-#define DA_PUSH_MULT(da, buf, n) {\
+#define DA_PUSH_MULT(da, buf, n) do {\
 	DA_FIT(da, DA_LEN(da) + n);\
 	memcpy(&(da)[DA_HEADER(da)->count], buf, n * sizeof(*(da)));\
 	DA_HEADER(da)->count += n;\
-}
+} while(0)
 
 #define DA_FOR(da, name)\
 	for (typeof(da) name = (da); name < &(da)[DA_LEN(da)]; name++)
 
 #define DA_FORVAL(da, name)\
-	for (volatile typeof(*(da)) *da_iter = (da), name; da_iter < &(da)[DA_LEN(da)] && (name = *da_iter, 1); da_iter++)
+	for (volatile typeof(*(da)) *stdwrm__da_iter = (da), name; stdwrm__da_iter < &(da)[DA_LEN(da)] && (name = *stdwrm__da_iter, 1); stdwrm__da_iter++)
 
 #endif
diff --git a/ihash.h b/ihash.h
new file mode 100644
index 0000000..242e97c
--- /dev/null
+++ b/ihash.h
@@ -0,0 +1,109 @@
+#ifndef IHASH_H
+#define IHASH_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include "dynarr.h"
+#include "str.h"
+
+#ifndef IHASH_SLOTS
+#define IHASH_SLOTS 8192
+#endif
+
+typedef uint64_t hash_t;
+
+typedef struct {
+	intptr_t key;
+	void *value;
+	hash_t hash;
+} IntHashEntry;
+
+typedef struct {
+	DYNARR(IntHashEntry) entries;
+} IntHashSlot;
+
+typedef struct {
+	IntHashSlot slots[IHASH_SLOTS];
+} IntHashTable;
+
+hash_t ihash(intptr_t s);
+void ihash_init(IntHashTable *h);
+void ihash_free(IntHashTable *h);
+void *ihash_get(IntHashTable *h, intptr_t key);
+void ihash_put(IntHashTable *h, intptr_t key, void *value);
+IntHashEntry *ihash_find(IntHashTable *h, intptr_t key);
+
+#ifdef IHASH_IMPL
+
+/* murmur64 integer hash */
+
+hash_t ihash(intptr_t h) {
+	h *= h >> 33;
+	h *= 0xff51afd7ed558ccdL;
+	h *= h >> 33;
+	h *= 0xc4ceb9fe1a85ec53L;
+	h *= h >> 33;
+	return h;
+}
+
+/* hash table */
+
+void ihash_init(IntHashTable *h) {
+	*h = (IntHashTable) { 0 };
+}
+
+void ihash_free(IntHashTable *h) {
+	for (unsigned i = 0; i < IHASH_SLOTS; i++) {
+		IntHashSlot *s = &h->slots[i];
+		if (!s->entries) continue;
+		DA_FREE(s->entries);
+	}
+}
+
+static inline int ihash_entry_match(IntHashEntry *h, intptr_t s, hash_t ihash) {
+	return s == ihash;
+}
+
+static inline IntHashEntry *ihash_find_hashed(IntHashTable *h, intptr_t key, hash_t k) {
+	size_t i = k & (IHASH_SLOTS - 1);
+	if (h->slots[i].entries) {
+		DA_FOR(h->slots[i].entries, e) {
+			if (ihash_entry_match(e, key, k)) {
+				return e;
+			}
+		}
+	}
+	return NULL;
+}
+
+IntHashEntry *ihash_find(IntHashTable *h, intptr_t key) {
+	return ihash_find_hashed(h, key, ihash(key));
+}
+
+void *ihash_get(IntHashTable *h, intptr_t key) {
+	IntHashEntry *e = ihash_find(h, key);
+	return e ? e->value : NULL;
+}
+
+void ihash_put(IntHashTable *h, intptr_t key, void *value) {
+	hash_t keyh = ihash(key);
+	IntHashEntry *e = ihash_find_hashed(h, key, keyh);
+	if (e) {
+		e->value = value;
+	} else {
+		hash_t keyi = keyh & (IHASH_SLOTS - 1);
+		if (!h->slots[keyi].entries) {
+			DA_INIT(h->slots[keyi].entries);
+		}
+		DA_PUSH(h->slots[keyi].entries, (IntHashEntry) {
+			.key = key,
+			.value = value,
+			.hash = keyh
+		});
+	}
+}
+
+#endif
+#endif
diff --git a/shash.h b/shash.h
index 537449e..e039ebb 100644
--- a/shash.h
+++ b/shash.h
@@ -5,7 +5,6 @@
 #include <stdint.h>
 #include <ctype.h>
 
-#include "stdwrm.h"
 #include "dynarr.h"
 #include "str.h"
 
@@ -36,7 +35,7 @@ void *shash_get(StrHashTable *h, strv_t key);
 void shash_put(StrHashTable *h, strv_t key, void *value);
 StrHashEntry *shash_find(StrHashTable *h, strv_t key);
 
-#ifdef STDWRM_IMPL_SHASH
+#ifdef SHASH_IMPL
 
 /* hacky FNV-1a hash */
 
@@ -44,7 +43,7 @@ StrHashEntry *shash_find(StrHashTable *h, strv_t key);
 #define FNV_OFFSET_BASIS (hash_t)14695981039346656037LU
 hash_t shash(strv_t s) {
 	hash_t h = FNV_OFFSET_BASIS;
-	for (size_t i = 0; i < s.n; i++) h = (h ^ s.s[i]) * FNV_64_PRIME;
+	for (size_t i = 0; i < s.n; i++) h = (h ^ (s.s[i] & 255)) * FNV_64_PRIME;
 	return h;
 }
 
diff --git a/stdwrm.h b/stdwrm.h
index 1ee7281..46992c3 100644
--- a/stdwrm.h
+++ b/stdwrm.h
@@ -2,8 +2,10 @@
 #define STDWRM_H
 
 #ifdef STDWRM_IMPL
-#define STDWRM_IMPL_SHASH
-#define STDWRM_IMPL_STR
+#define SHASH_IMPL
+#define IHASH_IMPL
+#define ZONE_IMPL
+#define STR_IMPL
 #endif
 
 #endif
diff --git a/str.h b/str.h
index 47ff676..9848983 100644
--- a/str.h
+++ b/str.h
@@ -3,7 +3,6 @@
 
 #include <string.h>
 
-#include "stdwrm.h"
 #include "dynarr.h"
 
 typedef DYNARR(char) string;
@@ -14,14 +13,20 @@ typedef struct {
 } strv_t;
 
 #define strv(s) (strv_t) { s, strlen(s) }
+#define strvs(s) (strv_t) { s, slen(s) }
 
 string snew(void);
 size_t slen(const string);
 void scats(string *, strv_t);
 void scatc(string *, char);
 void sfree(string);
+void sreplace(string *str, size_t i, size_t n, strv_t with);
+string sfmt(const char *fmt, ...);
+string sdup(const char *);
 
-#ifdef STDWRM_IMPL_STR
+#ifdef STR_IMPL
+
+#include <stdarg.h>
 
 string snew(void) {
 	string s;
@@ -54,5 +59,37 @@ void sfree(string s) {
 	DA_FREE(s);
 }
 
+string sfmt(const char *fmt, ...) {
+	va_list count, print;
+	string s;
+	FILE *f = fopen("/dev/null", "w/o");
+	va_start(print, fmt);
+	va_copy(count, print);
+	size_t n = vfprintf(f, fmt, count) + 1;
+	DA_INIT_SZ(s, n);
+	vsprintf(s, fmt, print);
+	va_end(print);
+	fclose(f);
+	return s;
+}
+
+string sdup(const char *s) {
+	string d;
+	size_t n = strlen(s) + 1;
+	DA_INIT_SZ(d, n);
+	memcpy(d, s, n);
+	return d;
+}
+
+void sreplace(string *str, size_t i, size_t n, strv_t with) {
+	string s = *str;
+	size_t new_n = DA_LEN(s) + with.n - n;
+	DA_FIT(s, new_n);
+	memmove(&s[i + with.n], &s[i + n], slen(s) - (i + n));
+	memcpy(&s[i], with.s, with.n);
+	s[new_n - 1] = 0;
+	DA_LEN(s) = new_n;
+}
+
 #endif
 #endif
diff --git a/strio.h b/strio.h
index 20d0ddf..0395dd7 100644
--- a/strio.h
+++ b/strio.h
@@ -5,17 +5,24 @@
 
 #include "str.h"
 
+#ifndef STRIO_CHUNK_SIZE
+#define STRIO_CHUNK_SIZE 256
+#endif
+
 string read_whole_file(FILE *f);
 
-#ifdef STDWRM_IMPL_STR
+#ifdef STR_IMPL
+
+#include <stdio.h>
 
 string read_whole_file(FILE *f) {
-	char chunk[256];
 	string s;
-	DA_INIT(s);
+	DA_INIT_SZ(s, STRIO_CHUNK_SIZE);
 	while (!feof(f)) {
-		size_t n = fread(chunk, 1, sizeof chunk, f);
-		DA_PUSH_MULT(s, chunk, n);
+		char *buf = &s[DA_LEN(s)];
+		size_t n = fread(buf, 1, STRIO_CHUNK_SIZE, f);
+		DA_FIT(s, DA_LEN(s) + n);
+		DA_LEN(s) += n;
 	}
 	DA_PUSH(s, 0);
 	return s;
diff --git a/typ.h b/typ.h
new file mode 100644
index 0000000..02174be
--- /dev/null
+++ b/typ.h
@@ -0,0 +1,33 @@
+#ifndef TYP_H
+#define TYP_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef uint8_t  u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef int8_t  i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+
+typedef float f32;
+typedef double f64;
+
+typedef size_t usize;
+typedef ptrdiff_t isize;
+
+typedef intptr_t iptr;
+typedef uintptr_t uptr;
+
+typedef u8  uchar8;
+typedef u16 uchar16;
+typedef u32 uchar32;
+typedef i8  ichar8;
+typedef i16 ichar16;
+typedef i32 ichar32;
+
+#endif
diff --git a/zone.h b/zone.h
new file mode 100644
index 0000000..d10ef6e
--- /dev/null
+++ b/zone.h
@@ -0,0 +1,291 @@
+#ifndef ZONE_H
+#define ZONE_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define ZONE_USE_MALLOC         0
+#define ZONE_USE_MMAP           1
+#define ZONE_USE_WASM_BULKMEM   2
+
+#ifndef ZONE_BACKEND
+	#ifdef __unix__
+		#define ZONE_BACKEND ZONE_USE_MMAP
+	#else
+		#define ZONE_BACKEND ZONE_USE_MALLOC
+	#endif
+#endif
+
+#if !defined(ZONE_NOSTDLIB) && (ZONE_BACKEND != ZONE_USE_MMAP && ZONE_BACKEND != ZONE_USE_MALLOC)
+	#define ZONE_NOSTDLIB
+#endif
+
+typedef struct ZoneFrame ZoneFrame;
+struct ZoneFrame {
+	ZoneFrame *prev, *next;
+	uint8_t *beg, *end;
+	uint8_t data[];
+};
+
+typedef struct ZoneState ZoneState;
+
+struct ZoneState {
+	ZoneFrame *zf;
+	ZoneState *last;
+	uint8_t *beg;
+};
+
+typedef struct {
+	ZoneFrame *cur, *tail;
+	ZoneState *last;
+} Zone;
+
+void zn_free(Zone *z);
+void zn_reset(Zone *z);
+
+void zn_begin(Zone *z);
+void zn_end(Zone *z);
+void zn_save(Zone *z, ZoneState *m);
+void zn_load(Zone *z, ZoneState *m);
+
+void *zn_alloc(Zone *z, ptrdiff_t n);
+void *zn_alloc_align(Zone *z, ptrdiff_t n, size_t align);
+void *zn_realloc(Zone *z, void *ptr, ptrdiff_t oldsz, ptrdiff_t newsz);
+void *zn_realloc_align(Zone *z, void *ptr, ptrdiff_t oldsz, ptrdiff_t newsz, size_t align);
+
+char *zn_strdup(Zone *z, const char *s);
+void *zn_zeroed(void *, size_t);
+
+#define zn_new(z, t) (t*)zn_zeroed(zn_alloc_align(z, sizeof(t), _Alignof(t)), sizeof(t))
+
+#ifdef ZONE_IMPL
+
+#ifndef ZONE_PAGE_MULT
+#define ZONE_PAGE_MULT 2
+#endif
+
+#define UPTR_ALIGN(x, align) ((x)+((-x)&((align)-1)))
+#define PTR_ALIGN(ptr, align) (typeof(ptr)) (((uintptr_t)ptr + (align - 1)) & -align)
+
+#if ZONE_BACKEND == ZONE_USE_MMAP || ZONE_BACKEND == ZONE_USE_MALLOC
+	#include <stdio.h>
+	#include <stdlib.h>
+	[[noreturn]] void zn_abort(const char *msg) {
+		fprintf(stderr, "%s\n", msg);
+		abort();
+	}
+#elif ZONE_BACKEND == ZONE_USE_WASM_BULKMEM
+	__attribute((import_name("alert"))) void js_alert(const char *msg);
+	__attribute((import_name("abort"))) [[noreturn]] void js_abort(void);
+	[[noreturn]] void zn_abort(const char *msg) {
+		js_alert(msg);
+		js_abort();
+	}
+#else
+	#error "zn_abort not implemented for the current platform -- using __builtin_trap() instead"
+	[[noreturn]] void zn_abort(cont char *msg) {
+		(void)msg;
+		__builtin_trap();
+	}
+#endif
+
+#define ZONE_MEMSET __builtin_memset
+#define ZONE_MEMCPY __builtin_memcpy
+
+#if ZONE_BACKEND == ZONE_USE_MMAP
+
+	#include <sys/mman.h>
+	#include <unistd.h>
+
+	#define ZONE_PAGE_SIZE (ZONE_PAGE_MULT * sysconf(_SC_PAGE_SIZE))
+	#define ZONE_PAGE_FAIL MAP_FAILED
+
+	static void *zn_pg_alloc(size_t n) {
+		return mmap(NULL, n * ZONE_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	}
+	static void zn_pg_free(void *p, size_t n) {
+		munmap(p, n);
+	}
+
+#elif ZONE_BACKEND == ZONE_USE_MALLOC
+
+	#define ZONE_PAGE_SIZE (ZONE_PAGE_MULT * 4 * 1024)
+	#define ZONE_PAGE_FAIL NULL
+
+	static void *zn_pg_alloc(size_t n) {
+		return malloc(n * ZONE_PAGE_SIZE);
+	}
+	static void zn_pg_free(void *p, size_t n) {
+		free(p);
+	}
+
+#elif ZONE_BACKEND == ZONE_USE_WASM_BULKMEM
+
+	#define ZONE_PAGE_SIZE 65536
+	#define ZONE_PAGE_FAIL (void*)(uintptr_t)-1
+	extern uint8_t __heap_base;
+	static void *zn_pg_free_adr = 0;
+	static void *zn_pg_alloc(size_t n) {
+		if (zn_pg_free_adr) {
+			void *p = zn_pg_free_adr;
+			zn_pg_free_adr = *(void **)zn_pg_free_adr;
+			return p;
+		}
+		void *p = &__heap_base + __builtin_wasm_memory_size(0);
+		__builtin_wasm_memory_grow(0, 1);
+		return p;
+	}
+	static void zn_pg_free(void *p, size_t n) {
+		uintptr_t adr = ((uintptr_t)p & ~0xFFFF);
+		n = (n + 0xFFFF) >> 16;
+		while (n--) {
+			void *pg = (void *)(adr + (n << 16));
+			*(void **)pg = zn_pg_free_adr;
+			zn_pg_free_adr = pg;
+		}
+	}
+
+#else
+
+	#error "unknown or unsupported zone backend"
+
+#endif
+
+static inline size_t zn_pg_fit(size_t cap) {
+	return cap + (-cap & (ZONE_PAGE_SIZE - 1));
+}
+
+static ZoneFrame *zn_zf_new(size_t capacity) {
+	ZoneFrame *zf = zn_pg_alloc(capacity / ZONE_PAGE_SIZE);
+	if (zf == ZONE_PAGE_FAIL) zn_abort("failed to allocate zone frame\n");
+	zf->prev = NULL;
+	zf->next = NULL;
+	zf->beg = zf->data;
+	zf->end = (uint8_t*)zf + capacity;
+	return zf;
+}
+
+static void zn_zf_free(ZoneFrame *z) {
+	zn_pg_free(z, (uintptr_t)z->end - (uintptr_t)z->beg);
+}
+
+void *zn_alloc_align(Zone *z, ptrdiff_t n, size_t align) {
+	ZoneFrame *zf = z->cur;
+	uint8_t *aligned;
+	for (;;) {
+		if (!zf) {
+			zf = zn_zf_new(zn_pg_fit(n + sizeof(ZoneFrame) + align - 1));
+			zf->prev = z->tail;
+			if (z->tail) z->tail->next = zf;
+			z->tail = zf;
+			z->cur = zf;
+		}
+		aligned = PTR_ALIGN(zf->beg, align);
+		if (aligned + n < zf->end) break;
+		zf = zf->next;
+	}
+	zf->beg = aligned + n;
+	return aligned;
+}
+
+void *zn_realloc_align(Zone *z, void *ptr, ptrdiff_t oldsz, ptrdiff_t newsz, size_t align) {
+	if (!ptr || !oldsz) return zn_alloc_align(z, newsz, align);
+	if (z->cur && ptr == z->cur->beg - oldsz && z->cur->beg - oldsz + newsz < z->cur->end) {
+		z->cur->beg -= oldsz;
+		z->cur->beg += newsz;
+		return ptr;
+	} else {
+		void *p = zn_alloc_align(z, newsz, align);
+		ZONE_MEMCPY(p, ptr, oldsz);
+		return p;
+	}
+}
+
+static inline size_t zn_align_for(size_t n) {
+	size_t a = 1;
+	while (n > a) a <<= 1;
+	return a;
+}
+
+void *zn_alloc(Zone *z, ptrdiff_t n) {
+	return zn_alloc_align(z, n, zn_align_for(n));
+}
+
+void *zn_realloc(Zone *z, void *ptr, ptrdiff_t oldsz, ptrdiff_t newsz) {
+	return zn_realloc_align(z, ptr, oldsz, newsz, zn_align_for(newsz));
+}
+
+void *zn_calloc(Zone *z, size_t n, size_t size) {
+	void *p = zn_alloc_align(z, n * size, zn_align_for(size));
+	ZONE_MEMSET(p, 0, n * size);
+	return p;
+}
+
+void zn_free(Zone *z) {
+	ZoneFrame *a = z->tail, *b;
+	while (a) {
+		b = a->prev;
+		zn_zf_free(a);
+		a = b;
+	}
+}
+
+void zn_reset(Zone *z) {
+	ZoneFrame *zf = z->tail;
+	while (zf) {
+		zf->beg = zf->data;
+		if (!zf->prev) break;
+		zf = zf->prev;
+	}
+	if (zf) z->cur = zf;
+}
+
+void zn_save(Zone *z, ZoneState *m) {
+	m->zf = z->cur;
+	m->beg = z->cur ? z->cur->beg : 0;
+	m->last = z->last;
+}
+
+void zn_load(Zone *z, ZoneState *m) {
+	if (m->zf) {
+		while (z->cur != m->zf) {
+			z->cur->beg = z->cur->data;
+			z->cur = z->cur->prev;
+		}
+		m->zf->beg = m->beg;
+	} else {
+		zn_reset(z);
+	}
+	z->last = m->last;
+}
+
+/* utils */
+
+#ifndef ZONE_NOSTDLIB
+char *zn_strdup(Zone *z, const char *s) {
+	size_t n = strlen(s) + 1;
+	char *d = zn_alloc_align(z, n, 1);
+	ZONE_MEMCPY(d, s, n);
+	return d;
+}
+#endif
+
+void *zn_zeroed(void *ptr, size_t n) {
+	ZONE_MEMSET(ptr, 0, n);
+	return ptr;
+}
+
+void zn_begin(Zone *z) {
+	ZoneState m = { 0 };
+	zn_save(z, &m);
+	ZoneState *p = zn_new(z, ZoneState);
+	*p = m;
+	z->last = p;
+}
+
+void zn_end(Zone *z) {
+	zn_load(z, z->last);
+}
+
+#endif
+#endif