sic

The sic programming language, compiler and tools (WIP)
Log | Files | Refs

commit 49885c39ef3d0b4067d7e4532e4816f79ed42c59
parent f57583bece1d460cec1a66c374c9651321a28113
Author: keyle <keyle@capsule.org>
Date:   Thu, 25 Jun 2026 23:04:25 +1000

early buffer string pool impl

Diffstat:
Asrc/buffer.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/buffer.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/src/buffer.c b/src/buffer.c @@ -0,0 +1,127 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "buffer.h" + +#define BUFFER_SIZE (8 * 1024 * 1024) + +typedef struct buffer_block { + struct buffer_block *next; + size_t len; + size_t cap; + char data[]; +}; + +struct buffer_block * +buf_new_block(size_t mincap) { + size_t cap = BUFFER_SIZE; + struct buffer_block *b; + + if (cap < mincap) { cap = mincap; } + + if (cap > SIZE_MAX - sizeof(struct buffer_block)) { + fprintf(stderr, "buffer_block: size overflow\n"); + exit(1); + } + + b = malloc(sizeof(struct buffer_block) + cap); + if (!b) { + fprintf(stderr, "buffer_block: could not allocate %zu bytes\n", cap); + exit(1); + } + + b->next = NULL; + b->len = 0; + b->cap = cap; + + return b; +} + +void * +buf_pool_alloc(struct buffer *buf, size_t size) { + struct buffer_block *b; + void *ptr; + + if (!buf->current) { + buf->head = buf->current = buf_new_block(size); + } + + if (size > buf->current->cap - buf->current->len) { + b = buf_new_block(size); + buf->current->next = b; + buf->current = b; + } + + ptr = buf->current->data + buf->current->len; + buf->current->len += size; // TODO fine for string but needs to be aligned if used for structs. + + return ptr; +} + +char * +buf_strn(struct buffer *buf, char *s, size_t len) { + char *dst; + if (len == SIZE_MAX) { + fprintf(stderr, "buffer_block: too large\n"); + exit(1); + } + + dst = buf_pool_alloc(buf, len + 1); + memcpy(dst, s, len); + dst[len] = '\0'; + + return dst; +} + +char * +buf_str(struct buffer *buf, char *s) { + return buf_strn(buf, s, strlen(s)); +} + +char * +buf_vfmt(struct buffer *buf, const char *fmt, va_list args) { + va_list copy; + int needed; + char *dst; + va_copy(copy, args); + + needed = vsnprintf(NULL, 0, fmt, copy); + va_end(copy); + if (needed < 0) { + fprintf(stderr, "fmt: formatting failed\n"); + exit(1); + } + + dst = buf_pool_alloc(buf, (size_t)needed + 1); + vsnprintf(dst, (size_t)needed + 1, fmt, args); + + return dst; +} + +void +buf_reset(struct buffer *buf) { + struct buffer_block *b; + + for (b = buf->head; b; b = b->next) { + b->len = 0; + } + + buf->current = buf->head; +} + +void +buf_free_all(struct buffer *buf) { + struct buffer_block *b = buf->head; + struct buffer_block *next_b; + + while (b) { + next_b = b->next; + free(b); + b = next_b; + } + + buf->head = NULL; + buf->current = NULL; +} diff --git a/src/buffer.h b/src/buffer.h @@ -0,0 +1,47 @@ +#pragma once + +#include <stdarg.h> +#include <stddef.h> + +// note utf-16 currently not supported + +typedef struct buffer_block Buffer_Block; + +typedef struct buffer { + Buffer_Block *head; + Buffer_Block *current; +} Buffer; + +void *buf_pool_alloc(struct buffer *buf, size_t size); +char *buf_strn(struct buffer *buf, char *s, size_t len); +char *buf_str(struct buffer *buf, char *s); +char *buf_vfmt(struct buffer *buf, const char *fmt, va_list args); +void buf_reset(struct buffer *buf); +void buf_free_all(struct buffer *buf); + +#define BUFFER_DEFINE(prefix) \ + static Buffer prefix##_buffer = {0}; \ + \ + static inline char *prefix##_strn(char *s, size_t len) { \ + return buf_strn(&prefix##_buffer, s, len); \ + } \ + \ + static inline char *prefix##_str(char *s) { \ + return buf_str(&prefix##_buffer, s); \ + } \ + \ + static inline char *prefix##_fmt(char *fmt, ...) { \ + va_list args; \ + va_start(args, fmt); \ + char *result = buf_vfmt(&prefix##_buffer, fmt, args); \ + va_end(args); \ + return result; \ + } \ + \ + static inline void prefix##_reset(void) { \ + buf_reset(&prefix##_buffer); \ + } \ + \ + static inline void prefix##_free_all(void) { \ + buf_free_all(&prefix##_buffer); \ + }