summaryrefslogtreecommitdiff
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