fu/c/common.c

57 lines
1.6 KiB
C

/* Custom string builder, should be slightly faster than using Sv* macros directly. */
typedef struct {
SV *sv;
char *cur;
char *end;
} fustr;
static void fustr_init_(pTHX_ fustr *s, size_t prealloc) {
s->sv = sv_2mortal(newSV(prealloc));
SvPOK_only(s->sv);
s->cur = SvPVX(s->sv);
s->end = SvEND(s->sv);
}
static void fustr_grow(pTHX_ fustr *s, size_t add) {
size_t off = s->cur - SvPVX(s->sv);
size_t newlen = 64;
add += off;
/* Increment to next power of two; SvGROW's default strategy is slow */
while (newlen < add) newlen <<= 1;
char *buf = SvGROW(s->sv, newlen);
s->cur = buf + off;
s->end = buf + SvLEN(s->sv);
}
static inline void fustr_reserve_(pTHX_ fustr *s, size_t add) {
if (UNLIKELY(s->end < s->cur + add)) fustr_grow(aTHX_ s, add);
}
static inline void fustr_write_(pTHX_ fustr *s, const char *str, size_t n) {
fustr_reserve_(aTHX_ s, n);
memcpy(s->cur, str, n);
s->cur += n;
}
/* Adds n uninitialized bytes to the string and returns a buffer to write the data to */
static inline char *fustr_write_buf_(pTHX_ fustr *s, size_t n) {
fustr_reserve_(aTHX_ s, n);
char *buf = s->cur;
s->cur += n;
return buf;
}
static SV *fustr_done_(pTHX_ fustr *s) {
fustr_reserve_(aTHX_ s, 1);
*s->cur = 0;
SvCUR_set(s->sv, s->cur - SvPVX(s->sv));
// TODO: SvPV_shrink_to_cur?
return s->sv;
}
#define fustr_init(a,b) fustr_init_(aTHX_ a,b)
#define fustr_reserve(a,b) fustr_reserve_(aTHX_ a,b)
#define fustr_write(a,b,c) fustr_write_(aTHX_ a,b,c)
#define fustr_write_buf(a,b) fustr_write_buf_(aTHX_ a,b)
#define fustr_done(a) fustr_done_(aTHX_ a)