| |
| |
| |
| #include "utils.h" |
|
|
| |
| |
| |
|
|
| static ArenaBlock *arena_new_block(size_t min_size) { |
| size_t sz = min_size > ARENA_BLOCK_SIZE ? min_size : ARENA_BLOCK_SIZE; |
| ArenaBlock *b = (ArenaBlock *)malloc(sizeof(ArenaBlock) + sz); |
| if (!b) { fprintf(stderr, "OOM in arena\n"); exit(1); } |
| b->next = NULL; |
| b->size = sz; |
| b->used = 0; |
| return b; |
| } |
|
|
| Arena *arena_create(void) { |
| Arena *a = (Arena *)calloc(1, sizeof(Arena)); |
| a->head = a->current = arena_new_block(ARENA_BLOCK_SIZE); |
| a->total_alloc = 0; |
| return a; |
| } |
|
|
| void *arena_alloc(Arena *a, size_t size) { |
| |
| size = (size + 7) & ~(size_t)7; |
| if (a->current->used + size > a->current->size) { |
| ArenaBlock *nb = arena_new_block(size); |
| a->current->next = nb; |
| a->current = nb; |
| } |
| void *p = a->current->data + a->current->used; |
| a->current->used += size; |
| a->total_alloc += size; |
| return p; |
| } |
|
|
| char *arena_strdup(Arena *a, const char *s) { |
| size_t len = strlen(s); |
| char *p = (char *)arena_alloc(a, len + 1); |
| memcpy(p, s, len + 1); |
| return p; |
| } |
|
|
| char *arena_strndup(Arena *a, const char *s, size_t n) { |
| char *p = (char *)arena_alloc(a, n + 1); |
| memcpy(p, s, n); |
| p[n] = '\0'; |
| return p; |
| } |
|
|
| void arena_destroy(Arena *a) { |
| ArenaBlock *b = a->head; |
| while (b) { |
| ArenaBlock *next = b->next; |
| free(b); |
| b = next; |
| } |
| free(a); |
| } |
|
|
| |
| |
| |
|
|
| void strbuf_init(StrBuf *sb) { |
| sb->data = NULL; |
| sb->len = 0; |
| sb->cap = 0; |
| } |
|
|
| static void strbuf_grow(StrBuf *sb, size_t need) { |
| if (sb->len + need + 1 > sb->cap) { |
| sb->cap = sb->cap ? sb->cap * 2 : 256; |
| while (sb->cap < sb->len + need + 1) sb->cap *= 2; |
| sb->data = (char *)realloc(sb->data, sb->cap); |
| if (!sb->data) { fprintf(stderr, "OOM in strbuf\n"); exit(1); } |
| } |
| } |
|
|
| void strbuf_append(StrBuf *sb, const char *fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| |
| va_list ap2; |
| va_copy(ap2, ap); |
| int n = vsnprintf(NULL, 0, fmt, ap2); |
| va_end(ap2); |
| if (n < 0) { va_end(ap); return; } |
| strbuf_grow(sb, (size_t)n); |
| vsnprintf(sb->data + sb->len, (size_t)n + 1, fmt, ap); |
| sb->len += (size_t)n; |
| va_end(ap); |
| } |
|
|
| void strbuf_append_char(StrBuf *sb, char c) { |
| strbuf_grow(sb, 1); |
| sb->data[sb->len++] = c; |
| sb->data[sb->len] = '\0'; |
| } |
|
|
| void strbuf_append_indent(StrBuf *sb, int indent) { |
| for (int i = 0; i < indent; i++) |
| strbuf_append(sb, " "); |
| } |
|
|
| char *strbuf_detach(StrBuf *sb) { |
| char *s = sb->data; |
| sb->data = NULL; |
| sb->len = sb->cap = 0; |
| return s; |
| } |
|
|
| void strbuf_free(StrBuf *sb) { |
| free(sb->data); |
| sb->data = NULL; |
| sb->len = sb->cap = 0; |
| } |
|
|
| |
| |
| |
|
|
| static int error_count = 0; |
| static int warn_count = 0; |
|
|
| void p2s_error(SourceLoc loc, const char *fmt, ...) { |
| fprintf(stderr, "\033[1;31merror\033[0m"); |
| if (loc.filename) |
| fprintf(stderr, " [%s:%d:%d]", loc.filename, loc.line, loc.col); |
| fprintf(stderr, ": "); |
| va_list ap; |
| va_start(ap, fmt); |
| vfprintf(stderr, fmt, ap); |
| va_end(ap); |
| fprintf(stderr, "\n"); |
| error_count++; |
| } |
|
|
| void p2s_warn(SourceLoc loc, const char *fmt, ...) { |
| fprintf(stderr, "\033[1;33mwarning\033[0m"); |
| if (loc.filename) |
| fprintf(stderr, " [%s:%d:%d]", loc.filename, loc.line, loc.col); |
| fprintf(stderr, ": "); |
| va_list ap; |
| va_start(ap, fmt); |
| vfprintf(stderr, fmt, ap); |
| va_end(ap); |
| fprintf(stderr, "\n"); |
| warn_count++; |
| } |
|
|
| void p2s_note(const char *fmt, ...) { |
| fprintf(stderr, "\033[1;36mnote\033[0m: "); |
| va_list ap; |
| va_start(ap, fmt); |
| vfprintf(stderr, fmt, ap); |
| va_end(ap); |
| fprintf(stderr, "\n"); |
| } |
|
|
| void p2s_fatal(const char *fmt, ...) { |
| fprintf(stderr, "\033[1;31mfatal\033[0m: "); |
| va_list ap; |
| va_start(ap, fmt); |
| vfprintf(stderr, fmt, ap); |
| va_end(ap); |
| fprintf(stderr, "\n"); |
| exit(1); |
| } |
|
|
| |
| |
| |
|
|
| static uint32_t hash_str(const char *s) { |
| uint32_t h = 5381; |
| while (*s) h = h * 33 + (unsigned char)*s++; |
| return h; |
| } |
|
|
| HashMap *hashmap_create(void) { |
| HashMap *m = (HashMap *)calloc(1, sizeof(HashMap)); |
| m->cap = HASHMAP_INIT_CAP; |
| m->buckets = (HashEntry **)calloc(m->cap, sizeof(HashEntry *)); |
| m->len = 0; |
| return m; |
| } |
|
|
| void hashmap_put(HashMap *m, const char *key, void *val) { |
| uint32_t idx = hash_str(key) % m->cap; |
| |
| for (HashEntry *e = m->buckets[idx]; e; e = e->next) { |
| if (strcmp(e->key, key) == 0) { |
| e->val = val; |
| return; |
| } |
| } |
| |
| HashEntry *e = (HashEntry *)malloc(sizeof(HashEntry)); |
| e->key = strdup(key); |
| e->val = val; |
| e->next = m->buckets[idx]; |
| m->buckets[idx] = e; |
| m->len++; |
| |
| if (m->len > m->cap * 3 / 4) { |
| size_t newcap = m->cap * 2; |
| HashEntry **newb = (HashEntry **)calloc(newcap, sizeof(HashEntry *)); |
| for (size_t i = 0; i < m->cap; i++) { |
| HashEntry *cur = m->buckets[i]; |
| while (cur) { |
| HashEntry *next = cur->next; |
| uint32_t ni = hash_str(cur->key) % newcap; |
| cur->next = newb[ni]; |
| newb[ni] = cur; |
| cur = next; |
| } |
| } |
| free(m->buckets); |
| m->buckets = newb; |
| m->cap = newcap; |
| } |
| } |
|
|
| void *hashmap_get(HashMap *m, const char *key) { |
| uint32_t idx = hash_str(key) % m->cap; |
| for (HashEntry *e = m->buckets[idx]; e; e = e->next) |
| if (strcmp(e->key, key) == 0) return e->val; |
| return NULL; |
| } |
|
|
| bool hashmap_has(HashMap *m, const char *key) { |
| uint32_t idx = hash_str(key) % m->cap; |
| for (HashEntry *e = m->buckets[idx]; e; e = e->next) |
| if (strcmp(e->key, key) == 0) return true; |
| return false; |
| } |
|
|
| void hashmap_destroy(HashMap *m) { |
| for (size_t i = 0; i < m->cap; i++) { |
| HashEntry *e = m->buckets[i]; |
| while (e) { |
| HashEntry *next = e->next; |
| free(e->key); |
| free(e); |
| e = next; |
| } |
| } |
| free(m->buckets); |
| free(m); |
| } |
|
|
| |
| |
| |
|
|
| char *read_file(const char *path, size_t *out_len) { |
| FILE *f = fopen(path, "rb"); |
| if (!f) { |
| fprintf(stderr, "Cannot open file: %s\n", path); |
| return NULL; |
| } |
| fseek(f, 0, SEEK_END); |
| long len = ftell(f); |
| fseek(f, 0, SEEK_SET); |
| char *buf = (char *)malloc((size_t)len + 1); |
| if (!buf) { fclose(f); return NULL; } |
| fread(buf, 1, (size_t)len, f); |
| buf[len] = '\0'; |
| fclose(f); |
| if (out_len) *out_len = (size_t)len; |
| return buf; |
| } |
|
|