--- JSON-XS/XS.xs 2007/06/11 03:18:07 1.38 +++ JSON-XS/XS.xs 2007/06/12 01:27:02 1.40 @@ -180,7 +180,6 @@ if (is_utf8) { - //uch = utf8n_to_uvuni (str, end - str, &clen, UTF8_CHECK_ONLY); uch = decode_utf8 (str, end - str, &clen); if (clen == (STRLEN)-1) croak ("malformed or illegal unicode character in string [%.11s], cannot convert to JSON", str); @@ -499,6 +498,7 @@ } else if (SvNOKp (sv)) { + // trust that perl will do the right thing w.r.t. JSON syntax. need (enc, NV_DIG + 32); Gconvert (SvNVX (sv), NV_DIG, 0, enc->cur); enc->cur += strlen (enc->cur); @@ -508,6 +508,7 @@ // we assume we can always read an IV as a UV if (SvUV (sv) & ~(UV)0x7fff) { + // large integer, use the (rather slow) snprintf way. need (enc, sizeof (UV) * 3); enc->cur += SvIsUV(sv) @@ -520,6 +521,7 @@ // code will likely be branchless and use only a single multiplication I32 i = SvIV (sv); U32 u; + char digit, nz = 0; need (enc, 6); @@ -529,13 +531,16 @@ // convert to 4.28 fixed-point representation u = u * ((0xfffffff + 10000) / 10000); // 10**5, 5 fractional digits - char digit, nz = 0; - + // now output digit by digit, each time masking out the integer part + // and multiplying by 5 while moving the decimal point one to the right, + // resulting in a net multiplication by 10. + // we always write the digit to memory but conditionally increment + // the pointer, to ease the usage of conditional move instructions. digit = u >> 28; *enc->cur = digit + '0'; enc->cur += (nz = nz || digit); u = (u & 0xfffffff) * 5; digit = u >> 27; *enc->cur = digit + '0'; enc->cur += (nz = nz || digit); u = (u & 0x7ffffff) * 5; digit = u >> 26; *enc->cur = digit + '0'; enc->cur += (nz = nz || digit); u = (u & 0x3ffffff) * 5; digit = u >> 25; *enc->cur = digit + '0'; enc->cur += (nz = nz || digit); u = (u & 0x1ffffff) * 5; - digit = u >> 24; *enc->cur = digit + '0'; enc->cur += 1; + digit = u >> 24; *enc->cur = digit + '0'; enc->cur += 1; // correctly generate '0' } } else if (SvROK (sv)) @@ -627,10 +632,10 @@ signed char d1, d2, d3, d4; unsigned char *cur = (unsigned char *)dec->cur; - d1 = decode_hexdigit [cur [0]]; if (expect_false (d1 < 0)) ERR ("four hexadecimal digits expected"); - d2 = decode_hexdigit [cur [1]]; if (expect_false (d2 < 0)) ERR ("four hexadecimal digits expected"); - d3 = decode_hexdigit [cur [2]]; if (expect_false (d3 < 0)) ERR ("four hexadecimal digits expected"); - d4 = decode_hexdigit [cur [3]]; if (expect_false (d4 < 0)) ERR ("four hexadecimal digits expected"); + d1 = decode_hexdigit [cur [0]]; if (expect_false (d1 < 0)) ERR ("exactly four hexadecimal digits expected"); + d2 = decode_hexdigit [cur [1]]; if (expect_false (d2 < 0)) ERR ("exactly four hexadecimal digits expected"); + d3 = decode_hexdigit [cur [2]]; if (expect_false (d3 < 0)) ERR ("exactly four hexadecimal digits expected"); + d4 = decode_hexdigit [cur [3]]; if (expect_false (d4 < 0)) ERR ("exactly four hexadecimal digits expected"); dec->cur += 4; @@ -863,7 +868,7 @@ if (*start == '-') switch (dec->cur - start) { - case 2: return newSViv (-( start [1] - '0' )); + case 2: return newSViv (-( start [1] - '0' * 1)); case 3: return newSViv (-( start [1] * 10 + start [2] - '0' * 11)); case 4: return newSViv (-( start [1] * 100 + start [2] * 10 + start [3] - '0' * 111)); case 5: return newSViv (-(start [1] * 1000 + start [2] * 100 + start [3] * 10 + start [4] - '0' * 1111)); @@ -871,7 +876,7 @@ else switch (dec->cur - start) { - case 1: return newSViv ( start [0] - '0' ); + case 1: return newSViv ( start [0] - '0' * 1); case 2: return newSViv ( start [0] * 10 + start [1] - '0' * 11); case 3: return newSViv ( start [0] * 100 + start [1] * 10 + start [2] - '0' * 111); case 4: return newSViv ( start [0] * 1000 + start [1] * 100 + start [2] * 10 + start [3] - '0' * 1111); @@ -888,9 +893,12 @@ } else return newSVuv (uv); + + // here would likely be the place for bigint support } } + // if we ever support bigint or bigfloat, this is the place for bigfloat return newSVnv (Atof (start)); fail: @@ -1001,6 +1009,9 @@ decode_sv (dec_t *dec) { decode_ws (dec); + + // the beauty of JSON: you need exactly one character lookahead + // to parse anything. switch (*dec->cur) { case '"': ++dec->cur; return decode_str (dec); @@ -1140,8 +1151,6 @@ { int i; - memset (decode_hexdigit, 0xff, 256); - for (i = 0; i < 256; ++i) decode_hexdigit [i] = i >= '0' && i <= '9' ? i - '0'