feat: add auto-expanding buffer implementation for html writer

main
Jef Roosens 2024-03-16 13:35:12 +01:00
parent 33824534bc
commit 5c96031834
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
3 changed files with 121 additions and 0 deletions

View File

@ -11,6 +11,14 @@
*out = temp; \
}
#define MRK_MALLOC(out, size) \
{ \
void *temp = malloc(size); \
if (temp == NULL) \
return mrk_err_failed_alloc; \
*out = temp; \
}
#define MRK_RES(x) \
{ \
mrk_err res = x; \

View File

@ -0,0 +1,43 @@
#ifndef MRK_BUF
#define MRK_BUF
#include <stdlib.h>
#include "mrk/common.h"
/**
* Wrapper around a nul-terminated char buffer that grows as needed
*/
typedef struct mrk_buf {
char *s;
size_t len;
size_t cap;
} mrk_buf;
/**
* Initialize a (usually stack-allocated) buffer
*/
mrk_err mrk_buf_init(mrk_buf *buf);
/**
* Double the buffer's internal capacity until it has enough
* room for the additional elements.
*/
mrk_err mrk_buf_expand(mrk_buf *buf, size_t required);
/**
* Shrink the internal buffer so that its capacity equals the stored length.
*/
mrk_err mrk_buf_compact(mrk_buf *buf);
/**
* Append the given nul-terminated string to the stored string.
*/
mrk_err mrk_buf_append(mrk_buf *buf, const char *s);
/**
* Append the char buffer with the given length to the stored string.
*/
mrk_err mrk_buf_append_n(mrk_buf *buf, const char *s, size_t len);
#endif

70
src/buf.c 100644
View File

@ -0,0 +1,70 @@
#include <string.h>
#include "mrk/buf.h"
mrk_err mrk_buf_init(mrk_buf *buf) {
MRK_MALLOC(&buf->s, 2);
// 2 ^ 0
buf->cap = 1;
buf->len = 0;
buf->s[buf->len] = '\0';
return mrk_err_ok;
}
mrk_err mrk_buf_expand(mrk_buf *buf, size_t required) {
size_t new_cap = buf->cap;
while (buf->len + required >= new_cap) {
// Grow buffer size in powers of two
new_cap <<= 1;
}
// No need to reallocate if there's already enough space
if (new_cap == buf->cap) {
return mrk_err_ok;
}
char *new_buf = realloc(buf->s, new_cap + 1);
if (new_buf == NULL) {
return mrk_err_failed_alloc;
}
buf->s = new_buf;
buf->cap = new_cap;
return mrk_err_ok;
}
mrk_err mrk_buf_compact(mrk_buf *buf) {
char *new_buf = realloc(buf->s, buf->len + 1);
if (new_buf == NULL) {
return mrk_err_failed_alloc;
}
buf->s = new_buf;
buf->cap = buf->len;
return mrk_err_ok;
}
mrk_err mrk_buf_append(mrk_buf *buf, const char *s) {
size_t len = strlen(s);
return mrk_buf_append_n(buf, s, len);
}
mrk_err mrk_buf_append_n(mrk_buf *buf, const char *s, size_t len) {
MRK_RES(mrk_buf_expand(buf, len));
memcpy(&buf->s[buf->len], s, len);
buf->len += len;
// Keep the buffer nul-terminated
buf->s[buf->len] = '\0';
return mrk_err_ok;
}