| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "mds_buf.h" |
|
2
|
|
|
|
|
|
|
#include |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
/* Measured output/input ratios per bench corpus: |
|
5
|
|
|
|
|
|
|
* progit (prose) 1.04 |
|
6
|
|
|
|
|
|
|
* commonmark-spec 1.12 |
|
7
|
|
|
|
|
|
|
* synth-prose 1.21 |
|
8
|
|
|
|
|
|
|
* synth-tables 2.08 \u2190 dominates the high end |
|
9
|
|
|
|
|
|
|
* Old heuristic was a flat 1.25\u00d7 + 64, which under-allocated by 2 grows |
|
10
|
|
|
|
|
|
|
* on table-heavy inputs (a 1MB synth-tables corpus triggered two |
|
11
|
|
|
|
|
|
|
* SvGROW realloc-copies of >1 MB each). New heuristic samples up to |
|
12
|
|
|
|
|
|
|
* 4 KB of the head of the input to estimate pipe density; high pipe |
|
13
|
|
|
|
|
|
|
* density (table corpora) gets 2.25\u00d7, everything else gets 1.50\u00d7. |
|
14
|
|
|
|
|
|
|
* The 64-byte slack remains so tiny inputs never start at zero. */ |
|
15
|
2444
|
|
|
|
|
|
static size_t mds_buf_predict_cap(const char* s, size_t hint) { |
|
16
|
|
|
|
|
|
|
size_t scan; |
|
17
|
2444
|
|
|
|
|
|
size_t pipes = 0, newlines = 0; |
|
18
|
|
|
|
|
|
|
int table_heavy; |
|
19
|
|
|
|
|
|
|
size_t cap; |
|
20
|
|
|
|
|
|
|
size_t i; |
|
21
|
|
|
|
|
|
|
|
|
22
|
2444
|
100
|
|
|
|
|
if (hint == 0) return 64; |
|
23
|
2442
|
|
|
|
|
|
scan = hint < 4096 ? hint : 4096; |
|
24
|
2442
|
50
|
|
|
|
|
if (s) { |
|
25
|
73940
|
100
|
|
|
|
|
for (i = 0; i < scan; i++) { |
|
26
|
71498
|
|
|
|
|
|
unsigned char c = (unsigned char)s[i]; |
|
27
|
71498
|
|
|
|
|
|
pipes += (c == '|'); |
|
28
|
71498
|
|
|
|
|
|
newlines += (c == '\n'); |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
/* Table heuristic: average >= 1 pipe per line in the sampled head. */ |
|
32
|
2442
|
100
|
|
|
|
|
table_heavy = (newlines && pipes >= newlines); |
|
|
|
100
|
|
|
|
|
|
|
33
|
2442
|
|
|
|
|
|
cap = table_heavy |
|
34
|
71
|
|
|
|
|
|
? hint + (hint >> 1) + (hint >> 2) + 64 /* ~2.25\u00d7 */ |
|
35
|
2442
|
100
|
|
|
|
|
: hint + (hint >> 1) + 64; /* ~1.50\u00d7 */ |
|
36
|
2442
|
|
|
|
|
|
return cap; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
1
|
|
|
|
|
|
void mds_buf_init(pTHX_ mds_buf* b, SV* sv, size_t hint) { |
|
40
|
|
|
|
|
|
|
size_t cap; |
|
41
|
1
|
|
|
|
|
|
b->sv = sv; |
|
42
|
1
|
|
|
|
|
|
cap = mds_buf_predict_cap(SvPVX(sv), hint); |
|
43
|
|
|
|
|
|
|
/* Note: at this point sv has no PV yet; the predictor falls into the |
|
44
|
|
|
|
|
|
|
* `s == NULL` branch and returns the prose-default 1.5\u00d7. Callers |
|
45
|
|
|
|
|
|
|
* that want table-density sizing should call mds_buf_init_for_input |
|
46
|
|
|
|
|
|
|
* below with the input pointer. */ |
|
47
|
1
|
50
|
|
|
|
|
SvUPGRADE(sv, SVt_PV); |
|
48
|
1
|
50
|
|
|
|
|
SvGROW(sv, cap); |
|
|
|
50
|
|
|
|
|
|
|
49
|
1
|
|
|
|
|
|
SvCUR_set(sv, 0); |
|
50
|
1
|
|
|
|
|
|
SvPOK_on(sv); |
|
51
|
1
|
|
|
|
|
|
b->base = SvPVX(sv); |
|
52
|
1
|
|
|
|
|
|
b->cur = b->base; |
|
53
|
1
|
|
|
|
|
|
b->end = b->base + SvLEN(sv) - 1; /* keep room for NUL */ |
|
54
|
1
|
|
|
|
|
|
*b->cur = '\0'; |
|
55
|
1
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
2443
|
|
|
|
|
|
void mds_buf_init_for_input(pTHX_ mds_buf* b, SV* sv, |
|
58
|
|
|
|
|
|
|
const char* input, size_t hint) { |
|
59
|
|
|
|
|
|
|
size_t cap; |
|
60
|
2443
|
|
|
|
|
|
b->sv = sv; |
|
61
|
2443
|
|
|
|
|
|
cap = mds_buf_predict_cap(input, hint); |
|
62
|
2443
|
50
|
|
|
|
|
SvUPGRADE(sv, SVt_PV); |
|
63
|
2443
|
50
|
|
|
|
|
SvGROW(sv, cap); |
|
|
|
50
|
|
|
|
|
|
|
64
|
2443
|
|
|
|
|
|
SvCUR_set(sv, 0); |
|
65
|
2443
|
|
|
|
|
|
SvPOK_on(sv); |
|
66
|
2443
|
|
|
|
|
|
b->base = SvPVX(sv); |
|
67
|
2443
|
|
|
|
|
|
b->cur = b->base; |
|
68
|
2443
|
|
|
|
|
|
b->end = b->base + SvLEN(sv) - 1; |
|
69
|
2443
|
|
|
|
|
|
*b->cur = '\0'; |
|
70
|
2443
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
82
|
|
|
|
|
|
MDS_COLD void mds_buf_reserve(pTHX_ mds_buf* b, size_t need) { |
|
73
|
82
|
|
|
|
|
|
size_t used = (size_t)(b->cur - b->base); |
|
74
|
82
|
|
|
|
|
|
size_t cap = SvLEN(b->sv); |
|
75
|
82
|
|
|
|
|
|
size_t want = used + need + 1; |
|
76
|
|
|
|
|
|
|
size_t newcap; |
|
77
|
82
|
50
|
|
|
|
|
if (want <= cap) { |
|
78
|
|
|
|
|
|
|
/* SvGROW may have been a no-op; just refresh end */ |
|
79
|
0
|
|
|
|
|
|
b->end = b->base + cap - 1; |
|
80
|
0
|
|
|
|
|
|
return; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
82
|
50
|
|
|
|
|
newcap = cap ? cap : 64; |
|
83
|
164
|
100
|
|
|
|
|
while (newcap < want) newcap = newcap + (newcap >> 1) + 64; /* 1.5x */ |
|
84
|
|
|
|
|
|
|
/* materialise current cursor into SvCUR so SvGROW preserves it */ |
|
85
|
82
|
|
|
|
|
|
SvCUR_set(b->sv, used); |
|
86
|
82
|
50
|
|
|
|
|
SvGROW(b->sv, newcap); |
|
|
|
50
|
|
|
|
|
|
|
87
|
82
|
|
|
|
|
|
b->base = SvPVX(b->sv); |
|
88
|
82
|
|
|
|
|
|
b->cur = b->base + used; |
|
89
|
82
|
|
|
|
|
|
b->end = b->base + SvLEN(b->sv) - 1; |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
2444
|
|
|
|
|
|
void mds_buf_finalize(pTHX_ mds_buf* b) { |
|
93
|
2444
|
|
|
|
|
|
size_t used = (size_t)(b->cur - b->base); |
|
94
|
2444
|
|
|
|
|
|
SvCUR_set(b->sv, used); |
|
95
|
2444
|
50
|
|
|
|
|
if (b->base) b->base[used] = '\0'; |
|
96
|
2444
|
|
|
|
|
|
SvPOK_on(b->sv); |
|
97
|
2444
|
|
|
|
|
|
} |