summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zone.h97
1 files changed, 97 insertions, 0 deletions
diff --git a/zone.h b/zone.h
new file mode 100644
index 0000000..4daa2fa
--- /dev/null
+++ b/zone.h
@@ -0,0 +1,97 @@
+#ifndef ZONE_H
+#define ZONE_H
+
+#include <stdint.h>
+
+#define ZONE_FRAME_CAPACITY_DEFAULT 1024
+
+typedef struct ZoneFrame ZoneFrame;
+struct ZoneFrame {
+ ZoneFrame *prev, *next;
+ size_t length, capacity;
+ uintptr_t data[];
+};
+
+typedef struct {
+ ZoneFrame *tail, *here;
+} Zone;
+
+void zn_free(Zone *z);
+void zn_clear(Zone *z);
+
+void *zn_alloc(Zone *z, size_t n);
+char *zn_strdup(Zone *z, const char *s);
+
+#ifdef ZONE_IMPL
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "zone.h"
+
+static ZoneFrame *zn_new_frame(size_t capacity) {
+ ZoneFrame *zf = malloc(sizeof *zf + capacity * sizeof(uintptr_t));
+ if (!zf) {
+ fprintf(stderr, "failed to allocate memory zone frame\n");
+ abort();
+ }
+ zf->prev = NULL;
+ zf->next = NULL;
+ zf->length = 0;
+ zf->capacity = capacity;
+ return zf;
+}
+
+void *zn_alloc(Zone *z, size_t n) {
+ ZoneFrame *zf = NULL;
+ size_t wordsz = (n + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
+ for (ZoneFrame *f = z->here; f; f = f->next) {
+ if (f->capacity - f->length >= wordsz) {
+ zf = f;
+ break;
+ }
+ }
+ if (!zf) {
+ size_t cap = ZONE_FRAME_CAPACITY_DEFAULT;
+ while (wordsz >= cap) cap <<= 1;
+ zf = zn_new_frame(cap);
+ zf->prev = z->tail;
+ if (z->tail) z->tail->next = zf;
+ z->tail = zf;
+ }
+ void *ptr = &zf->data[zf->length];
+ zf->length += wordsz;
+ z->here = zf;
+ return ptr;
+}
+
+void zn_free(Zone *z) {
+ ZoneFrame *p, *t;
+ t = z->tail;
+ while (t) {
+ p = t->prev;
+ free(t);
+ t = p;
+ }
+}
+
+void zn_clear(Zone *z) {
+ ZoneFrame *zf = z->here;
+ if (!zf) return;
+ for (;;) {
+ zf->length = 0;
+ if (zf->prev) zf = zf->prev;
+ else break;
+ }
+ z->tail = zf;
+}
+
+char *zn_strdup(Zone *z, const char *s) {
+ size_t n = strlen(s) + 1;
+ char *d = zn_alloc(z, n);
+ memcpy(d, s, n);
+ return d;
+}
+
+#endif
+#endif