aboutsummaryrefslogtreecommitdiffhomepage
path: root/mem.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-05-10 20:38:32 +0200
committerlemon <lsof@mailbox.org>2023-05-10 20:38:32 +0200
commit9100ed2b5dd01df8e6b766c7bc2a12c0dd44f1ff (patch)
tree0598b126bdddb7db462a2f0915e272d4345c0c39 /mem.c
initial commit
Diffstat (limited to 'mem.c')
-rw-r--r--mem.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/mem.c b/mem.c
new file mode 100644
index 0000000..11c1c8c
--- /dev/null
+++ b/mem.c
@@ -0,0 +1,117 @@
+#include "common.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+
+#define ALLOCERR(f) do { \
+ efmt("%s: %s\n", f, strerror(errno)); \
+ ioflush(&bstdout); \
+ ioflush(&bstderr); \
+ abort(); \
+} while (0)
+
+static void *
+xcalloc(size_t n, const char *f)
+{
+ void *p = calloc(n, 1);
+ if (!p) ALLOCERR(f);
+ return p;
+}
+
+static void *
+xrealloc(void *p, size_t n, const char *f)
+{
+ p = p ? realloc(p, n) : malloc(n);
+ if (!p) ALLOCERR(f);
+ return p;
+}
+
+/* vec: when _cap < 0, buf is dynamic allocated, otherwise an user provided buf */
+
+void
+vinit_(void **p, int *pcap, void *inlbuf, int cap, uint siz)
+{
+ assert(!*p);
+ *pcap = cap;
+ if (inlbuf) {
+ *p = inlbuf;
+ } else if (cap) {
+ *p = xrealloc(0, cap*siz, "vinit");
+ *pcap = -cap;
+ }
+}
+
+void
+vpush_(void **p, int *pcap, uint *pn, uint siz)
+{
+ if (*pn == *pcap) { /* empty or inline buffer */
+ int cap = *pcap ? *pcap * 2 : 8;
+ *p = xrealloc(NULL, cap * siz, "vpush");
+ *pcap = -cap;
+ } else if (*pn == -*pcap) { /* dyn buf */
+ *p = xrealloc(*p, -(*pcap *= 2) * siz, "vpush");
+ }
+ assert(-(volatile int)*pcap > *pn && "overflow");
+}
+
+void *
+vpushn_(void **p, int *pcap, uint *pn, uint siz, const void *dat, uint ndat)
+{
+ void *beg;
+
+ for (uint i = 0; i < ndat; ++i)
+ vpush_(p, pcap, pn, siz);
+ beg = (char *)*p + *pn * siz;
+ memcpy(beg, dat, ndat * siz);
+ *pn += ndat;
+ return beg;
+}
+
+struct arena *
+newarena(uint chunksiz)
+{
+ struct arena *ar = xcalloc(offsetof(struct arena, mem) + chunksiz, "newarena");
+ assert(chunksiz < 1u<<31 && "toobig");
+ ar->cap = chunksiz;
+ ar->dyn = 1;
+ return ar;
+}
+
+void *
+alloc(struct arena **par, uint siz, uint align)
+{
+ uint idx;
+ struct arena *new;
+
+ if (siz > (*par)->cap) {
+ new = newarena(siz);
+ new->n = siz;
+ new->prev = (*par)->prev;
+ (*par)->prev = new;
+ return new->mem;
+ }
+ align = align ? align : sizeof(void *);
+ idx = (uchar *)alignup((uintptr_t)&(*par)->mem[(*par)->n], align) - (*par)->mem;
+ if ((*par)->cap - idx >= siz) {
+ (*par)->n = idx + siz;
+ return (*par)->mem + idx;
+ }
+ new = newarena((*par)->cap);
+ new->prev = *par;
+ *par = new;
+ new->n = siz;
+ return new->mem;
+}
+
+void
+freearena(struct arena *ar)
+{
+ struct arena *prev;
+ for (; ar; ar = prev) {
+ prev = ar->prev;
+ if (ar->dyn)
+ free(ar);
+ }
+}
+
+/* vim:set ts=3 sw=3 expandtab: */