jsonfmt: Fix threading support + memory leak bug
This commit is contained in:
parent
9c8ce3f782
commit
12326ca8e4
5 changed files with 79 additions and 69 deletions
76
c/common.c
76
c/common.c
|
|
@ -1,43 +1,57 @@
|
|||
/* Custom string builder, comparable to functionality provided by SV*
|
||||
* functions, but with less magic and better inlineable. */
|
||||
/* Custom string builder, should be slightly faster than using Sv* macros directly. */
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
size_t size;
|
||||
char *buf;
|
||||
SV *sv;
|
||||
char *cur;
|
||||
char *end;
|
||||
} 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_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(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);
|
||||
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);
|
||||
}
|
||||
|
||||
#define fustr_reserve(s, n) do {\
|
||||
if (UNLIKELY((s)->size < (s)->len + (n))) fustr_grow(s, n);\
|
||||
} while(0)
|
||||
static inline void fustr_reserve_(pTHX_ fustr *s, size_t add) {
|
||||
if (UNLIKELY(s->end < s->cur + add)) fustr_grow(aTHX_ s, add);
|
||||
}
|
||||
|
||||
#define fustr_write(s, str, n) do {\
|
||||
fustr_reserve(s, n);\
|
||||
memcpy((s)->buf+(s)->len, str, (n));\
|
||||
(s)->len += (n);\
|
||||
} while(0)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* 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 r;
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue