Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 246 lines (201 sloc) 6.387 kb
36b5369 @mnunberg initial commit
authored
1 /**
2 * This header file contains static functions adapted from
3 * Marc Lehmanns' JSON::XS, particularly because it's fast,
4 * doesn't seem to rely on any external structures, and because
5 * numeric conversions aren't my ideas of fun.
6 */
7
8 #ifndef JSONXS_INLINE_H_
9 #define JSONXS_INLINE_H_
10
11 #include "perl-jsonsl.h"
12 #if __GNUC__ >= 3
13 # define expect(expr,value) __builtin_expect ((expr), (value))
14 # define INLINE static inline
15 #else
16 # define expect(expr,value) (expr)
17 # define INLINE static
18 #endif
19
20 #define ERR die
21 #define expect_false(expr) expect ((expr) != 0, 0)
22 #define expect_true(expr) expect ((expr) != 0, 1)
23
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
24 #define jsonxs__atof_scan1(s,a,e,p,m) jsonxs__atof_scan1_THX(aTHX_ s,a,e,p,m)
36b5369 @mnunberg initial commit
authored
25 INLINE void
26 jsonxs__atof_scan1_THX(pTHX_ const char *s,
27 NV *accum, int *expo, int postdp,
28 int maxdepth)
29 {
30 UV uaccum = 0;
31 int eaccum = 0;
32
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
33 /* if we recurse too deep, skip all remaining digits
34 to avoid a stack overflow attack */
36b5369 @mnunberg initial commit
authored
35 if (expect_false (--maxdepth <= 0))
36 while (((U8)*s - '0') < 10)
37 ++s;
38
39 for (;;)
40 {
41 U8 dig = (U8)*s - '0';
42
43 if (expect_false (dig >= 10))
44 {
45 if (dig == (U8)((U8)'.' - (U8)'0'))
46 {
47 ++s;
48 jsonxs__atof_scan1(s, accum, expo, 1, maxdepth);
49 }
50 else if ((dig | ' ') == 'e' - '0')
51 {
52 int exp2 = 0;
53 int neg = 0;
54
55 ++s;
56
57 if (*s == '-')
58 {
59 ++s;
60 neg = 1;
61 }
62 else if (*s == '+')
63 ++s;
64
65 while ((dig = (U8)*s - '0') < 10)
66 exp2 = exp2 * 10 + *s++ - '0';
67
68 *expo += neg ? -exp2 : exp2;
69 }
70
71 break;
72 }
73
74 ++s;
75
76 uaccum = uaccum * 10 + dig;
77 ++eaccum;
78
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
79 /*
80 if we have too many digits, then recurse for more
81 we actually do this for rather few digits
82 */
36b5369 @mnunberg initial commit
authored
83 if (uaccum >= (UV_MAX - 9) / 10)
84 {
85 if (postdp) *expo -= eaccum;
86 jsonxs__atof_scan1 (s, accum, expo, postdp, maxdepth);
87 if (postdp) *expo += eaccum;
88
89 break;
90 }
91 }
92
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
93 /*
36b5369 @mnunberg initial commit
authored
94 // this relies greatly on the quality of the pow ()
95 // implementation of the platform, but a good
96 // implementation is hard to beat.
97 // (IEEE 754 conformant ones are required to be exact)
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
98 *
99 */
36b5369 @mnunberg initial commit
authored
100 if (postdp) *expo -= eaccum;
101 *accum += uaccum * Perl_pow (10., *expo);
102 *expo += eaccum;
103 }
104
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
105 #define jsonxs__atof(s) jsonxs__atof_THX(aTHX_ s)
36b5369 @mnunberg initial commit
authored
106 INLINE NV
107 jsonxs__atof_THX (pTHX_ const char *s)
108 {
109 NV accum = 0.;
110 int expo = 0;
111 int neg = 0;
112
113 if (*s == '-')
114 {
115 ++s;
116 neg = 1;
117 }
118
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
119 /* a recursion depth of ten gives us >>500 bits */
36b5369 @mnunberg initial commit
authored
120 jsonxs__atof_scan1(s, &accum, &expo, 0, 10);
121
122 return neg ? -accum : accum;
123 }
124
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
125 #define jsonxs_inline_process_number(s) jsonxs_inline_process_number_THX(aTHX_ s)
36b5369 @mnunberg initial commit
authored
126
127 INLINE SV *
128 jsonxs_inline_process_number_THX(pTHX_ const char *start)
129 {
130
131 int is_nv = 0;
132 const char *c = start;
133
134 if (*c == '-')
135 ++c;
136
137 if (*c == '0') {
138 ++c;
139 if (*c >= '0' && *c <= '9') {
140 ERR("malformed number (leading zero must not be followed by another digit)");
141 }
142 } else if (*c < '0' || *c > '9') {
143 ERR("malformed number (no digits after initial minus)");
144 } else {
145 do {
146 ++c;
147 } while (*c >= '0' && *c <= '9');
148 }
149
150 if (*c == '.') {
151 ++c;
152
153 if (*c < '0' || *c > '9')
154 ERR("malformed number (no digits after decimal point)");
155
156 do {
157 ++c;
158 } while (*c >= '0' && *c <= '9');
159
160 is_nv = 1;
161 }
162
163 if (*c == 'e' || *c == 'E') {
164 ++c;
165
166 if (*c == '-' || *c == '+')
167 ++c;
168
169 if (*c < '0' || *c > '9')
170 ERR("malformed number (no digits after exp sign)");
171
172 do {
173 ++c;
174 } while (*c >= '0' && *c <= '9');
175
176 is_nv = 1;
177 }
178
179 if (!is_nv) {
180 int len = c - start;
181
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
182 /* special case the rather common 1..5-digit-int case */
36b5369 @mnunberg initial commit
authored
183 if (*start == '-')
184 switch (len) {
185 case 2:
186 return newSViv (-(IV)( start [1] - '0' * 1));
187 case 3:
188 return newSViv (-(IV)( start [1] * 10 + start [2] - '0' * 11));
189 case 4:
190 return newSViv (-(IV)( start [1] * 100 + start [2] * 10 + start [3] - '0' * 111));
191 case 5:
192 return newSViv (-(IV)( start [1] * 1000 + start [2] * 100 + start [3] * 10 + start [4] - '0' * 1111));
193 case 6:
194 return newSViv (-(IV)(start [1] * 10000 + start [2] * 1000 + start [3] * 100 + start [4] * 10 + start [5] - '0' * 11111));
195 }
196 else
197 switch (len) {
198 case 1:
199 return newSViv ( start [0] - '0' * 1);
200 case 2:
201 return newSViv ( start [0] * 10 + start [1] - '0' * 11);
202 case 3:
203 return newSViv ( start [0] * 100 + start [1] * 10 + start [2] - '0' * 111);
204 case 4:
205 return newSViv ( start [0] * 1000 + start [1] * 100 + start [2] * 10 + start [3] - '0' * 1111);
206 case 5:
207 return newSViv ( start [0] * 10000 + start [1] * 1000 + start [2] * 100 + start [3] * 10 + start [4] - '0' * 11111);
208 }
209
210 {
211 UV uv;
212 int numtype = grok_number (start, len, &uv);
213 if (numtype & IS_NUMBER_IN_UV
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
214 ) {
36b5369 @mnunberg initial commit
authored
215 if (numtype & IS_NUMBER_NEG)
216 {
217 if (uv < (UV) IV_MIN
218 )
219 return newSViv (-(IV)uv);
220 } else
221 return newSVuv (uv);
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
222 }
36b5369 @mnunberg initial commit
authored
223 }
224
225 len -= *start == '-' ? 1 : 0;
226
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
227 /* does not fit into IV or UV, try NV */
36b5369 @mnunberg initial commit
authored
228 if (len <= NV_DIG
229 )
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
230 /* fits into NV without loss of precision */
36b5369 @mnunberg initial commit
authored
231 return newSVnv (jsonxs__atof (start));
232
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
233 /* everything else fails, convert it to a string */
36b5369 @mnunberg initial commit
authored
234 return newSVpvn (start, c - start);
235 }
236
1a2501d @mnunberg Tuba tuba tuba. also fixed compiler warnings and some more docs
authored
237 /* loss of precision here */
36b5369 @mnunberg initial commit
authored
238 return newSVnv (jsonxs__atof (start));
239 }
240
241 #undef ERR
242 #undef expect_false
243 #undef expect_true
244
245 #endif /* JSONXS_INLINE_H_ */
Something went wrong with that request. Please try again.