| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* mds_buf.h — output buffer wrapping a Perl SV. |
|
2
|
|
|
|
|
|
|
* |
|
3
|
|
|
|
|
|
|
* Owns a cursor into SvPV so we avoid SvCUR/SvLEN roundtrips per write. |
|
4
|
|
|
|
|
|
|
* Caller must call mds_buf_finalize() before the SV is consumed by Perl. |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
#ifndef MDS_BUF_H |
|
7
|
|
|
|
|
|
|
#define MDS_BUF_H |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#include |
|
10
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
11
|
|
|
|
|
|
|
#include "perl.h" |
|
12
|
|
|
|
|
|
|
#include "mds_compiler.h" |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
typedef struct mds_buf { |
|
15
|
|
|
|
|
|
|
SV* sv; |
|
16
|
|
|
|
|
|
|
char* base; /* SvPVX(sv) */ |
|
17
|
|
|
|
|
|
|
char* cur; /* write cursor */ |
|
18
|
|
|
|
|
|
|
char* end; /* base + SvLEN(sv) - 1 (room for trailing NUL) */ |
|
19
|
|
|
|
|
|
|
} mds_buf; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
/* Attach to an existing SV, predict initial capacity. */ |
|
22
|
|
|
|
|
|
|
void mds_buf_init(pTHX_ mds_buf* b, SV* sv, size_t hint); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
/* Input-aware initial capacity. Samples the head of |
|
25
|
|
|
|
|
|
|
* `input` for pipe density and picks 2.25\u00d7 for table-heavy inputs, |
|
26
|
|
|
|
|
|
|
* 1.50\u00d7 for everything else. Falls back to mds_buf_init's prose |
|
27
|
|
|
|
|
|
|
* default when input is NULL. */ |
|
28
|
|
|
|
|
|
|
void mds_buf_init_for_input(pTHX_ mds_buf* b, SV* sv, |
|
29
|
|
|
|
|
|
|
const char* input, size_t hint); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
/* Ensure at least `need` bytes free; grows SV and refreshes cursor. */ |
|
32
|
|
|
|
|
|
|
void mds_buf_reserve(pTHX_ mds_buf* b, size_t need); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
/* Append n bytes. The grow check is the only branch; the common case |
|
35
|
|
|
|
|
|
|
* (n bytes fit) compiles to a 2-instruction cursor bump + memcpy that |
|
36
|
|
|
|
|
|
|
* the optimiser turns into a register store when n is a compile-time |
|
37
|
|
|
|
|
|
|
* constant under 8. Marked always-inline so the constant-n cases at |
|
38
|
|
|
|
|
|
|
* call sites (HTML tags via MDS_BUF_LIT) really do specialise. */ |
|
39
|
|
|
|
|
|
|
MDS_ALWAYS_INLINE static void mds_buf_write(pTHX_ mds_buf* b, const char* s, size_t n) { |
|
40
|
30839
|
100
|
|
|
|
|
if (MDS_UNLIKELY(b->cur + n > b->end)) mds_buf_reserve(aTHX_ b, n); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
41
|
30839
|
|
|
|
|
|
memcpy(b->cur, s, n); |
|
42
|
30839
|
|
|
|
|
|
b->cur += n; |
|
43
|
30839
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
MDS_ALWAYS_INLINE static void mds_buf_putc(pTHX_ mds_buf* b, char c) { |
|
46
|
|
|
|
|
|
|
if (MDS_UNLIKELY(b->cur + 1 > b->end)) mds_buf_reserve(aTHX_ b, 1); |
|
47
|
|
|
|
|
|
|
*b->cur++ = c; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
/* Write a compile-time literal. */ |
|
51
|
|
|
|
|
|
|
#define MDS_BUF_LIT(b, lit) mds_buf_write(aTHX_ (b), "" lit, sizeof(lit) - 1) |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
/* Commit cursor to SvCUR, NUL-terminate. */ |
|
54
|
|
|
|
|
|
|
void mds_buf_finalize(pTHX_ mds_buf* b); |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
#endif |