#include "antcc.h" #include "u_hash.h" #include "u_bits.h" #include #include #include static void allocerr(void) { efmt("antcc fatal: %s\n", strerror(errno)); ioflush(&bstdout); ioflush(&bstderr); abort(); } void * xmalloc(size_t n) { void *p = malloc(n); if (!p) allocerr(); return p; } void * xcalloc(size_t n) { void *p = calloc(n, 1); if (!p) allocerr(); return p; } void * xrealloc(void *p, size_t n) { p = p ? realloc(p, n) : malloc(n); if (!p) allocerr(); return p; } /** string interning **/ internstr intern_(const char *s, uint len) { static uint N, n; static struct Ht { internstr s; size_t h; } *ht; static struct { char m[sizeof(Arena) + (2<<10)]; Arena *_a; } amem; static Arena *arena; if (!N) { ht = xcalloc((sizeof *ht) * (N = 1<<10)); arena = (void *)amem.m, arena->cap = sizeof amem.m - sizeof(Arena); } for (size_t h = len ? hashb(0, s, len) : hashs(0, s), i = h;;) { i &= N - 1; if (!ht[i].s) { /* insert */ if (n < N/4*3 /*load factor 75%*/) { ++n; ht[i].h = h; ht[i].s = alloccopy(&arena, s, (len ? len : strlen(s))+1, 1); if (len) ((char *)ht[i].s)[len] = 0; return ht[i].s; } /* resize */ size_t nnew = N * 2; struct Ht *new = xcalloc(sizeof *new * nnew); for (uint i = 0; i < N; ++i) { /* rehash */ if (!ht[i].s) continue; uint j = ht[i].h; while (new[j &= nnew-1].s) ++j; new[j] = ht[i]; } free(ht); ht = new; N = nnew; i = h; continue; } else if (h == ht[i].h) { if (!len && !strcmp(s, &ht[i].s->c)) return ht[i].s; else if (len && !strncmp(s, &ht[i].s->c, len) && ht[i].s[len].c == 0) return ht[i].s; } ++i; } } /** vec **/ void vinit_(struct vecbase *v, void *inlbuf, uint cap, uint siz) { assert(!v->p); v->cap = cap; if (inlbuf) { v->p = inlbuf; v->dyn = 0; } else if (cap) { v->p = xmalloc(cap*siz); v->dyn = 1; } } void vpush_(struct vecbase *v, uint siz) { if (v->n < v->cap) return; if (!v->dyn && v->n >= v->cap) { /* empty or inline buffer */ int cap = v->cap ? v->cap * 2 : 8; void *old = v->p; v->p = xmalloc(cap * siz); if (old) memcpy(v->p, old, v->cap * siz); v->cap = cap; v->dyn = 1; } else if (v->dyn && v->n >= v->cap) { /* dyn buf */ v->p = xrealloc(v->p, (v->cap *= 2) * siz); } while (v->n >= v->cap) v->p = xrealloc(v->p, (v->cap *= 2) * siz); assert(v->cap > v->n && "overflow"); } void * vpushn_(struct vecbase *v, uint siz, const void *dat, uint ndat) { void *beg; if (!ndat) return v->p; v->n += ndat; while (v->n >= v->cap) vpush_(v, siz); beg = (char *)v->p + (v->n - ndat) * siz; assert(dat); memcpy(beg, dat, ndat * siz); return beg; } void vresize_(struct vecbase *v, uint siz, uint N) { while (v->cap < N) { vpush_(v, siz); v->n = v->cap; } v->n = N; } /** arena **/ Arena * newarena(uint chunksiz) { Arena *ar = xmalloc(offsetof(Arena, mem) + chunksiz); assert(chunksiz < 1u<<31 && "toobig"); ar->prev = NULL; ar->cap = chunksiz; ar->dyn = 1; ar->n = 0; return ar; } void * alloc(Arena **par, uint siz, uint align) { uint idx; 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 * allocz(Arena **par, uint siz, uint align) { return memset(alloc(par, siz, align), 0, siz); } void freearena(Arena **par) { Arena *prev; for (; *par; *par = prev) { prev = (*par)->prev; if ((*par)->dyn) free(*par); else { if (prev) freearena(&prev); (*par)->prev = NULL; (*par)->n = 0; return; } } } /** pointer hashmap **/ void pmap_init_(struct pmapbase *m, void **v, uint vsiz, uint N) { assert(ispo2(N)); uint sizk = N*sizeof*m->k, sizv = N*vsiz; m->k = xcalloc(sizk + sizv); *v = (char *)m->k + sizk; m->N = N; } int pmap_get_(struct pmapbase *m, const void *k) { assert(k && "null key"); if (!m->N) return -1; for (size_t i = ptrhash(k);; ++i) { i &= m->N - 1; if (m->k[i] == k) return i; if (!m->k[i]) return -1; } } char pmap_tombstone_[1]; static void pmap_rehash(struct pmapbase *m, void **v, uint vsiz) { void **newk; int i, j; void *k; void *newv; uint N2 = m->N ? m->N << 1 : 16, sizk = N2*sizeof*m->k, sizv = N2*vsiz; assert(N2); newk = xcalloc(sizk + sizv); newv = (char *)newk + sizk; for (i = 0; i < m->N; ++i) { if (!m->k[i] || m->k[i] == pmap_tombstone_) continue; j = ptrhash(k = m->k[i]); for (;; ++j) { j &= N2 - 1; if (!newk[j]) { newk[j] = k; memcpy((char *)newv + j*vsiz, (char *)*v + i*vsiz, vsiz); break; } } } free(m->k); m->k = newk; *v = newv; m->N = N2; } int pmap_set_(struct pmapbase *m, void **v, uint vsiz, const void *k) { assert(k && "null key"); if (m->n >= m->N/4*3 /*load factor 75%*/) { pmap_rehash(m, v, vsiz); assert(m->n < m->N); } for (size_t i = ptrhash(k);; ++i) { i &= m->N - 1; if (m->k[i] == k) return i; if (!m->k[i] || m->k[i] == pmap_tombstone_) { m->k[i] = (void *)k; ++m->n; return i; } } } void pmap_del_(struct pmapbase *m, const void *k) { assert(k && "null key"); for (size_t i = ptrhash(k);; ++i) { i &= m->N - 1; if (m->k[i] == k) { m->k[i] = pmap_tombstone_; --m->n; return; } else if (!m->k[i]) return; } } /* vim:set ts=3 sw=3 expandtab: */