--- JSON-XS/XS.xs 2007/07/10 16:22:31 1.54 +++ JSON-XS/XS.xs 2007/08/26 22:27:32 1.62 @@ -2,10 +2,11 @@ #include "perl.h" #include "XSUB.h" -#include "assert.h" -#include "string.h" -#include "stdlib.h" -#include "stdio.h" +#include +#include +#include +#include +#include #if defined(__BORLANDC__) || defined(_MSC_VER) # define snprintf _snprintf // C compilers have this in stdio.h @@ -59,6 +60,14 @@ #define expect_false(expr) expect ((expr) != 0, 0) #define expect_true(expr) expect ((expr) != 0, 1) +#ifdef USE_ITHREADS +# define JSON_SLOW 1 +# define JSON_STASH (json_stash ? json_stash : gv_stashpv ("JSON::XS", 1)) +#else +# define JSON_SLOW 0 +# define JSON_STASH json_stash +#endif + static HV *json_stash, *json_boolean_stash; // JSON::XS:: static SV *json_true, *json_false; @@ -308,8 +317,14 @@ for (i = 0; i <= len; ++i) { + SV **svp = av_fetch (av, i, 0); + encode_indent (enc); - encode_sv (enc, *av_fetch (av, i, 0)); + + if (svp) + encode_sv (enc, *svp); + else + encode_str (enc, "null", 4, 0); if (i < len) encode_comma (enc); @@ -322,7 +337,7 @@ } static void -encode_he (enc_t *enc, HE *he) +encode_hk (enc_t *enc, HE *he) { encode_ch (enc, '"'); @@ -345,7 +360,6 @@ if (enc->json.flags & F_SPACE_BEFORE) encode_space (enc); encode_ch (enc, ':'); if (enc->json.flags & F_SPACE_AFTER ) encode_space (enc); - encode_sv (enc, HeVAL (he)); } // compare hash entries, used when all keys are bytestrings @@ -360,8 +374,8 @@ STRLEN la = HeKLEN (a); STRLEN lb = HeKLEN (b); - if (!(cmp = memcmp (HeKEY (a), HeKEY (b), la < lb ? la : lb))) - cmp = la - lb; + if (!(cmp = memcmp (HeKEY (b), HeKEY (a), lb < la ? lb : la))) + cmp = lb - la; return cmp; } @@ -370,29 +384,45 @@ static int he_cmp_slow (const void *a, const void *b) { - return sv_cmp (HeSVKEY_force (*(HE **)a), HeSVKEY_force (*(HE **)b)); + return sv_cmp (HeSVKEY_force (*(HE **)b), HeSVKEY_force (*(HE **)a)); } static void encode_hv (enc_t *enc, HV *hv) { - int count, i; + HE *he; + int count; if (enc->indent >= enc->maxdepth) croak ("data structure too deep (hit recursion limit)"); encode_ch (enc, '{'); encode_nl (enc); ++enc->indent; - if ((count = hv_iterinit (hv))) + // for canonical output we have to sort by keys first + // actually, this is mostly due to the stupid so-called + // security workaround added somewhere in 5.8.x. + // that randomises hash orderings + if (enc->json.flags & F_CANONICAL) { - // for canonical output we have to sort by keys first - // actually, this is mostly due to the stupid so-called - // security workaround added somewhere in 5.8.x. - // that randomises hash orderings - if (enc->json.flags & F_CANONICAL) + int count = hv_iterinit (hv); + + if (SvMAGICAL (hv)) + { + // need to count by iterating. could improve by dynamically building the vector below + // but I don't care for the speed of this special case. + // note also that we will run into undefined behaviour when the two iterations + // do not result in the same count, something I might care for in some later release. + + count = 0; + while (hv_iternext (hv)) + ++count; + + hv_iterinit (hv); + } + + if (count) { - int fast = 1; - HE *he; + int i, fast = 1; #if defined(__BORLANDC__) || defined(_MSC_VER) HE **hes = _alloca (count * sizeof (HE)); #else @@ -429,36 +459,37 @@ LEAVE; } - for (i = 0; i < count; ++i) + while (count--) { encode_indent (enc); - encode_he (enc, hes [i]); + he = hes [count]; + encode_hk (enc, he); + encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); - if (i < count - 1) + if (count) encode_comma (enc); } - - encode_nl (enc); } - else - { - HE *he = hv_iternext (hv); - + } + else + { + if (hv_iterinit (hv) || SvMAGICAL (hv)) + if ((he = hv_iternext (hv))) for (;;) { encode_indent (enc); - encode_he (enc, he); + encode_hk (enc, he); + encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); if (!(he = hv_iternext (hv))) break; encode_comma (enc); } - - encode_nl (enc); - } } + encode_nl (enc); + --enc->indent; encode_indent (enc); encode_ch (enc, '}'); } @@ -473,7 +504,11 @@ if (expect_false (SvOBJECT (sv))) { - if (SvSTASH (sv) == json_boolean_stash) + HV *stash = !JSON_SLOW || json_boolean_stash + ? json_boolean_stash + : gv_stashpv ("JSON::XS::Boolean", 1); + + if (SvSTASH (sv) == stash) { if (SvIV (sv)) encode_str (enc, "true", 4, 0); @@ -495,7 +530,6 @@ if (to_json) { - int count; dSP; ENTER; SAVETMPS; PUSHMARK (SP); @@ -933,9 +967,11 @@ if (!is_nv) { + int len = dec->cur - start; + // special case the rather common 1..4-digit-int case, assumes 32 bit ints or so if (*start == '-') - switch (dec->cur - start) + switch (len) { case 2: return newSViv (-( start [1] - '0' * 1)); case 3: return newSViv (-( start [1] * 10 + start [2] - '0' * 11)); @@ -943,7 +979,7 @@ case 5: return newSViv (-(start [1] * 1000 + start [2] * 100 + start [3] * 10 + start [4] - '0' * 1111)); } else - switch (dec->cur - start) + switch (len) { case 1: return newSViv ( start [0] - '0' * 1); case 2: return newSViv ( start [0] * 10 + start [1] - '0' * 11); @@ -953,7 +989,7 @@ { UV uv; - int numtype = grok_number (start, dec->cur - start, &uv); + int numtype = grok_number (start, len, &uv); if (numtype & IS_NUMBER_IN_UV) if (numtype & IS_NUMBER_NEG) { @@ -962,12 +998,24 @@ } else return newSVuv (uv); - - // here would likely be the place for bigint support } + + len -= *start == '-' ? 1 : 0; + + // does not fit into IV or UV, try NV + if ((sizeof (NV) == sizeof (double) && DBL_DIG >= len) + #if defined (LDBL_DIG) + || (sizeof (NV) == sizeof (long double) && LDBL_DIG >= len) + #endif + ) + // fits into NV without loss of precision + return newSVnv (Atof (start)); + + // everything else fails, convert it to a string + return newSVpvn (start, dec->cur - start); } - // if we ever support bigint or bigfloat, this is the place for bigfloat + // loss of precision here return newSVnv (Atof (start)); fail: @@ -1195,6 +1243,9 @@ if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) { dec->cur += 4; +#if JSON_SLOW + json_true = get_sv ("JSON::XS::true", 1); SvREADONLY_on (json_true); +#endif return SvREFCNT_inc (json_true); } else @@ -1206,6 +1257,9 @@ if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) { dec->cur += 5; +#if JSON_SLOW + json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); +#endif return SvREFCNT_inc (json_false); } else @@ -1342,6 +1396,11 @@ PROTOTYPES: DISABLE +void CLONE (...) + CODE: + json_stash = 0; + json_boolean_stash = 0; + void new (char *klass) PPCODE: { @@ -1349,7 +1408,7 @@ SvPOK_only (pv); Zero (SvPVX (pv), 1, JSON); ((JSON *)SvPVX (pv))->flags = F_DEFAULT; - XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), json_stash))); + XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), JSON_STASH))); } void ascii (JSON *self, int enable = 1)