File Coverage

encode_gen.h
Criterion Covered Total %
statement 107 124 86.2
branch 113 192 58.8
condition n/a
subroutine n/a
pod n/a
total 220 316 69.6


line stmt bran cond sub pod time code
1             // vim: filetype=xs
2              
3 47           STRLEN CONCAT(estimate_, NAME)(SV * sv){
4 47 50         if( sv!=NULL ){
    100          
5 46 100         if( SvROK(sv) && (!UNBLESSED || !sv_isobject(sv)) ){
    100          
    100          
6 21           SV * rvs = SvRV(sv);
7 27 100         for(int i=visited_p-1; i>=0; --i)
    100          
8 7 50         if( visited[i] == rvs )
    100          
9 1           return 4;
10 20           reserve_visited_capacity();
11 20           visited[visited_p++] = rvs;
12 20           switch( SvTYPE(rvs) ){
13             case SVt_PVAV: {
14 12           AV * av = (AV*) rvs;
15 12           SSize_t n = av_len(av);
16 12           if( n<0 ){
17 0           --visited_p;
18 0           return 2;
19             }
20              
21 12           STRLEN len = 2 + n;
22 12           SV ** elems = AvARRAY(av);
23 40 100         for(int i=0; i<=n; ++i)
    100          
24 28           len += CONCAT(estimate_, NAME)(elems[i]);
25 12           --visited_p;
26 12           return len;
27             }
28             case SVt_PVHV: {
29 3           HV * hv = (HV*) rvs;
30              
31 3           STRLEN len = 1;
32 3           hv_iterinit(hv);
33 6 0         for(HE * entry = hv_iternext(hv); entry; entry = hv_iternext(hv)){
    100          
34 3           len += 2; // : ,
35              
36             I32 keylen;
37 3           char * key = hv_iterkey(entry, &keylen);
38 3           len += estimate_str((unsigned char*)key, (STRLEN) keylen);
39              
40 3           SV * val = hv_iterval(hv, entry);
41 3           len += CONCAT(estimate_, NAME)(val);
42             }
43 3 0         if( len==1 )
    50          
44 0           ++len;
45 3           --visited_p;
46 3           return len;
47             }
48             default:
49 5           --visited_p;
50 5           break;
51             }
52 5 50         if( SvTYPE(rvs) < SVt_PVAV ){
    50          
53 5 50         NV nv = SvNV(rvs);
    100          
54             IV iv;
55 5           STRLEN len=0;
56 10 50         if( !Perl_isnan(nv) && nv == (NV)(iv = (IV) nv) ){
    50          
    50          
    50          
57 5 50         if( iv == 0 )
    50          
58 0           return 1;
59 5 50         if( iv < 0 )
    50          
60 0           ++len;
61 12 100         while( iv ){
    100          
62 7           ++len;
63 7           iv /= 10;
64             }
65             }
66             else{
67             char buffer[100];
68 0           snprintf(buffer, 100, "%g", (double) nv);
69 0 0         while( buffer[len] )
    0          
70 0           ++len;
71             }
72 5           return len;
73             }
74             }
75 25 50         if( SvOK(sv) ){
    0          
    0          
    100          
    50          
    50          
76             STRLEN len;
77 23 100         char * str = SvPV(sv, len);
    100          
78 23           return estimate_str((unsigned char*)str, len);
79             }
80             }
81 3           return 4;
82             }
83              
84 47           unsigned char * CONCAT(encode_, NAME)(unsigned char * buffer, SV * sv){
85 47 50         if( sv!=NULL ){
    100          
86 46 100         if( SvROK(sv) && (!UNBLESSED || !sv_isobject(sv)) ){
    100          
    100          
87 21           SV * rvs = SvRV(sv);
88 27 100         for(int i=visited_p-1; i>=0; --i)
    100          
89 7 50         if( visited[i] == rvs )
    100          
90 1           goto DEGENERATE;
91 20           reserve_visited_capacity();
92 20           visited[visited_p++] = rvs;
93 20           switch( SvTYPE(rvs) ){
94             case SVt_PVAV: {
95 12           *buffer++ = '[';
96              
97 12           AV * av = (AV*) rvs;
98 12           SSize_t n = av_len(av);
99 12           if( n>=0 ){
100 12           SV ** elems = AvARRAY(av);
101 28 100         for(int i=0; i
    100          
102 16           buffer = CONCAT(encode_, NAME)(buffer, elems[i]);
103 16           *buffer++ = ',';
104             }
105 12           buffer = CONCAT(encode_, NAME)(buffer, elems[n]);
106             }
107              
108 12           *buffer++ = ']';
109 12           --visited_p;
110 12           return buffer;
111             }
112             case SVt_PVHV: {
113 3           *buffer++ = '{';
114 3           HV * hv = (HV*) rvs;
115              
116 3           hv_iterinit(hv);
117 6 0         for(HE * entry = hv_iternext(hv); entry; entry = hv_iternext(hv)){
    100          
118              
119             I32 keylen;
120 3           char * key = hv_iterkey(entry, &keylen);
121 3           buffer = encode_str(buffer, (unsigned char*)key, (STRLEN) keylen);
122              
123 3           *buffer++ = ':';
124              
125 3           SV * val = hv_iterval(hv, entry);
126 3           buffer = CONCAT(encode_, NAME)(buffer, val);
127              
128 3           *buffer++ = ',';
129             }
130              
131 3 0         if( *(buffer-1) == '{' )
    50          
132 0           *buffer++ = '}';
133             else
134 3           *(buffer-1) = '}';
135 3           --visited_p;
136 3           return buffer;
137             }
138             default:
139 5           --visited_p;
140 5           break;
141             }
142 5 50         if( SvTYPE(rvs) < SVt_PVAV ){
    50          
143 5 50         NV nv = SvNV(rvs);
    100          
144             IV iv;
145 5 50         if( !Perl_isnan(nv) && nv == (NV)(iv = (IV) nv) ){
    50          
    50          
    50          
146 10 50         if( -59074 <= iv && iv <= 59074 ){
    50          
    50          
    50          
147             // (stolen from JSON::XS)
148             // optimise the "small number case"
149             // code will likely be branchless and use only a single multiplication
150             // works for numbers up to 59074
151             U32 u;
152 5           char digit, nz = 0;
153 5 50         if( iv < 0 ){
    50          
154 0           *buffer++ = '-';
155 0           u = -iv;
156             }
157             else
158 5           u = iv;
159             // convert to 4.28 fixed-point representation
160 5           u = u * ((0xfffffff + 10000) / 10000); // 10**5, 5 fractional digits
161              
162             // now output digit by digit, each time masking out the integer part
163             // and multiplying by 5 while moving the decimal point one to the right,
164             // resulting in a net multiplication by 10.
165             // we always write the digit to memory but conditionally increment
166             // the pointer, to enable the use of conditional move instructions.
167 5 50         digit = u >> 28; *buffer = digit + '0'; buffer += (nz = nz || digit); u = (u & 0xfffffffUL) * 5;
    50          
    50          
    50          
168 5 50         digit = u >> 27; *buffer = digit + '0'; buffer += (nz = nz || digit); u = (u & 0x7ffffffUL) * 5;
    50          
    50          
    50          
169 5 50         digit = u >> 26; *buffer = digit + '0'; buffer += (nz = nz || digit); u = (u & 0x3ffffffUL) * 5;
    50          
    50          
    50          
170 5 50         digit = u >> 25; *buffer = digit + '0'; buffer += (nz = nz || digit); u = (u & 0x1ffffffUL) * 5;
    50          
    50          
    100          
171 5           digit = u >> 24; *buffer = digit + '0'; buffer += 1; // correctly generate '0'
172             }
173             else{
174 0           snprintf((char*)buffer, 100, "%lld", (long long)iv);
175 0 0         while( *buffer )
    0          
176 0           ++buffer;
177             }
178             }
179             else{
180 0           snprintf((char*)buffer, 100, "%g", (double) nv);
181 0 0         while( *buffer )
    0          
182 0           ++buffer;
183             }
184 5           return buffer;
185             }
186             }
187 25 50         if( SvOK(sv) ){
    0          
    0          
    100          
    50          
    50          
188             STRLEN len;
189 23 100         char * str = SvPV(sv, len);
    100          
190 23           return encode_str(buffer, (unsigned char*)str, len);
191             }
192             }
193             DEGENERATE:
194 4           *buffer++ = 'n';
195 4           *buffer++ = 'u';
196 4           *buffer++ = 'l';
197 4           *buffer++ = 'l';
198 4           return buffer;
199             }
200