#ifndef ZONE_H #define ZONE_H #include #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); void *zn_zf_alloc(Zone *z, ZoneFrame **zf, size_t n); void *zn_zf_realloc(Zone *z, ZoneFrame **zf, void *ptr, size_t oldsz, size-t newsz); char *zn_strdup(Zone *z, const char *s); #ifdef ZONE_IMPL #include #include #include #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) { return zn_zf_alloc(z, NULL, n); } void *zn_zf_alloc(Zone *z, ZoneFrame **zfo, 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; if (zfo) *zfo = zf; return ptr; } void *zn_zf_realloc(Zone *z, ZoneFrame **zfo, void *old, size_t oldsz, size_t newsz) { ZoneFrame *zf = *zfo; size_t old_wordsz = (oldsz + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); size_t new_wordsz = (newsz + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); if (&zf->data[zf->length - old_wordsz] == old && zf->length + new_wordsz - old_wordsz <= zf->capacity) { zf->length = zf->length + new_wordsz - old_wordsz; return old; } else { void *new = zn_zf_alloc(z, zfo, newsz); zf->length -= old_wordsz; memcpy(new, old, oldsz); return new; } } 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