fu/c/common.c
Yorhel c16a9fa493 Add initial JSON formatter
It works and can format all "plain" Perl data, but has a few known bugs
and limitations that still need to be worked out.

It's about 8x smaller than JSON::XS's encoder and *much* smaller than
Cpanel::JSON::XS, but this is just a first attempt, it'll grow.
2025-01-28 09:33:29 +01:00

43 lines
1.2 KiB
C

/* Custom string builder, comparable to functionality provided by SV*
* functions, but with less magic and better inlineable. */
typedef struct {
size_t len;
size_t size;
char *buf;
} fustr;
/* No need to call this, an empty fustr is already usable.
* This allows setting a custom initial size. */
static void fustr_init(fustr *s, size_t prealloc) {
s->len = 0;
s->size = prealloc;
s->buf = safemalloc(prealloc);
}
static void fustr_grow(fustr *s, size_t add) {
if (s->size == 0) s->size = 512;
while (s->size < s->len + add)
s->size *= 2;
s->buf = saferealloc(s->buf, s->size);
}
#define fustr_reserve(s, n) do {\
if (UNLIKELY((s)->size < (s)->len + (n))) fustr_grow(s, n);\
} while(0)
#define fustr_write(s, str, n) do {\
fustr_reserve(s, n);\
memcpy((s)->buf+(s)->len, str, (n));\
(s)->len += (n);\
} while(0)
/* Move the string buffer into a new SV; fustr should be considered invalid after this call.
* Does not set the UTF8 flag. */
static SV *fustr_sv(fustr *s) {
SV *r = newSV(0);
fustr_write(s, "", 1); // trailing nul
sv_usepvn_flags(r, s->buf, s->len-1, SV_HAS_TRAILING_NUL);
// TODO: SvPV_shrink_to_cur?
return r;
}