oj 3.13.15 → 3.13.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +13 -13
- data/ext/oj/dump.c +2 -2
- data/ext/oj/dump_compat.c +5 -5
- data/ext/oj/dump_object.c +3 -3
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +14 -2
- data/ext/oj/object.c +9 -9
- data/ext/oj/oj.c +1 -0
- data/ext/oj/parse.c +112 -80
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +35 -4
- data/ext/oj/parser.h +1 -0
- data/ext/oj/rails.c +5 -5
- data/ext/oj/saj2.c +299 -45
- data/ext/oj/strict.c +13 -13
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +15 -15
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/version.rb +1 -1
- data/test/bar.rb +3 -8
- data/test/test_compat.rb +9 -0
- data/test/test_parser_saj.rb +55 -2
- metadata +2 -2
    
        data/ext/oj/parse.c
    CHANGED
    
    | @@ -183,6 +183,74 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) { | |
| 183 183 | 
             
                }
         | 
| 184 184 | 
             
            }
         | 
| 185 185 |  | 
| 186 | 
            +
            static inline const char *scan_string_noSIMD(const char *str, const char *end) {
         | 
| 187 | 
            +
                for (; '"' != *str; str++) {
         | 
| 188 | 
            +
                    if (end <= str || '\0' == *str || '\\' == *str) {
         | 
| 189 | 
            +
                        break;
         | 
| 190 | 
            +
                    }
         | 
| 191 | 
            +
                }
         | 
| 192 | 
            +
                return str;
         | 
| 193 | 
            +
            }
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            // Taken from Tensorflow:
         | 
| 196 | 
            +
            // https://github.com/tensorflow/tensorflow/blob/5dcfc51118817f27fad5246812d83e5dccdc5f72/tensorflow/core/lib/hash/crc32c_accelerate.cc#L21-L38
         | 
| 197 | 
            +
            #ifdef __SSE4_2__
         | 
| 198 | 
            +
            #if defined(__x86_64__) && defined(__GNUC__) && \
         | 
| 199 | 
            +
                (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
         | 
| 200 | 
            +
            #define USE_SSE_DETECT 1
         | 
| 201 | 
            +
            #elif defined(__x86_64__) && defined(__clang__)
         | 
| 202 | 
            +
            #if __has_builtin(__builtin_cpu_supports)
         | 
| 203 | 
            +
            #define USE_SSE_DETECT 1
         | 
| 204 | 
            +
            #endif
         | 
| 205 | 
            +
            #endif
         | 
| 206 | 
            +
            #endif /* __SSE4_2__ */
         | 
| 207 | 
            +
             | 
| 208 | 
            +
            // This version of Apple clang has a bug:
         | 
| 209 | 
            +
            // https://llvm.org/bugs/show_bug.cgi?id=25510
         | 
| 210 | 
            +
            #if defined(__APPLE__) && (__clang_major__ <= 8)
         | 
| 211 | 
            +
            #undef USE_SSE_DETECT
         | 
| 212 | 
            +
            #endif
         | 
| 213 | 
            +
             | 
| 214 | 
            +
            #ifdef USE_SSE_DETECT
         | 
| 215 | 
            +
            #include <nmmintrin.h>
         | 
| 216 | 
            +
             | 
| 217 | 
            +
            static inline const char *scan_string_SIMD(const char *str, const char *end) {
         | 
| 218 | 
            +
                static const char chars[16] = "\x00\\\"";
         | 
| 219 | 
            +
                const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
         | 
| 220 | 
            +
                const char *_end = (const char *)(end - 16);
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                for (; str <= _end; str += 16) {
         | 
| 223 | 
            +
                    const __m128i string = _mm_loadu_si128((const __m128i *)str);
         | 
| 224 | 
            +
                    const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
         | 
| 225 | 
            +
                    if (r != 16) {
         | 
| 226 | 
            +
                        str = (char*)(str + r);
         | 
| 227 | 
            +
                        return str;
         | 
| 228 | 
            +
                    }
         | 
| 229 | 
            +
                }
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                return scan_string_noSIMD(str, end);
         | 
| 232 | 
            +
            }
         | 
| 233 | 
            +
            #endif
         | 
| 234 | 
            +
             | 
| 235 | 
            +
            static bool cpu_supports_sse42(void) {
         | 
| 236 | 
            +
            #if USE_SSE_DETECT
         | 
| 237 | 
            +
                __builtin_cpu_init();
         | 
| 238 | 
            +
                return (__builtin_cpu_supports("sse4.2"));
         | 
| 239 | 
            +
            #else
         | 
| 240 | 
            +
                return false;
         | 
| 241 | 
            +
            #endif
         | 
| 242 | 
            +
            }
         | 
| 243 | 
            +
             | 
| 244 | 
            +
            static const char *(*scan_func) (const char *str, const char *end) = scan_string_noSIMD;
         | 
| 245 | 
            +
             | 
| 246 | 
            +
            void oj_scanner_init(void) {
         | 
| 247 | 
            +
                if (cpu_supports_sse42()) {
         | 
| 248 | 
            +
            #if USE_SSE_DETECT
         | 
| 249 | 
            +
                    scan_func = scan_string_SIMD;
         | 
| 250 | 
            +
            #endif
         | 
| 251 | 
            +
                }
         | 
| 252 | 
            +
            }
         | 
| 253 | 
            +
             | 
| 186 254 | 
             
            // entered at /
         | 
| 187 255 | 
             
            static void read_escaped_str(ParseInfo pi, const char *start) {
         | 
| 188 256 | 
             
                struct _buf buf;
         | 
| @@ -192,11 +260,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) { | |
| 192 260 | 
             
                Val         parent = stack_peek(&pi->stack);
         | 
| 193 261 |  | 
| 194 262 | 
             
                buf_init(&buf);
         | 
| 195 | 
            -
                 | 
| 196 | 
            -
             | 
| 197 | 
            -
                 | 
| 198 | 
            -
             | 
| 199 | 
            -
                    if ( | 
| 263 | 
            +
                buf_append_string(&buf, start, cnt);
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                for (s = pi->cur; '"' != *s;) {
         | 
| 266 | 
            +
                    const char *scanned = scan_func(s, pi->end);
         | 
| 267 | 
            +
                    if (scanned >= pi->end) {
         | 
| 200 268 | 
             
                        oj_set_error_at(pi,
         | 
| 201 269 | 
             
                                        oj_parse_error_class,
         | 
| 202 270 | 
             
                                        __FILE__,
         | 
| @@ -204,7 +272,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) { | |
| 204 272 | 
             
                                        "quoted string not terminated");
         | 
| 205 273 | 
             
                        buf_cleanup(&buf);
         | 
| 206 274 | 
             
                        return;
         | 
| 207 | 
            -
                    } | 
| 275 | 
            +
                    }
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                    buf_append_string(&buf, s, (size_t)(scanned - s));
         | 
| 278 | 
            +
                    s = scanned;
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                    if ('\\' == *s) {
         | 
| 208 281 | 
             
                        s++;
         | 
| 209 282 | 
             
                        switch (*s) {
         | 
| 210 283 | 
             
                        case 'n': buf_append(&buf, '\n'); break;
         | 
| @@ -273,8 +346,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) { | |
| 273 346 | 
             
                            buf_cleanup(&buf);
         | 
| 274 347 | 
             
                            return;
         | 
| 275 348 | 
             
                        }
         | 
| 276 | 
            -
             | 
| 277 | 
            -
                        buf_append(&buf, *s);
         | 
| 349 | 
            +
                        s++;
         | 
| 278 350 | 
             
                    }
         | 
| 279 351 | 
             
                }
         | 
| 280 352 | 
             
                if (0 == parent) {
         | 
| @@ -327,44 +399,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) { | |
| 327 399 | 
             
                buf_cleanup(&buf);
         | 
| 328 400 | 
             
            }
         | 
| 329 401 |  | 
| 330 | 
            -
            static inline void scan_string_noSIMD(ParseInfo pi) {
         | 
| 331 | 
            -
                for (; '"' != *pi->cur; pi->cur++) {
         | 
| 332 | 
            -
                    if (pi->end <= pi->cur || '\0' == *pi->cur || '\\' == *pi->cur) {
         | 
| 333 | 
            -
                        return;
         | 
| 334 | 
            -
                    }
         | 
| 335 | 
            -
                }
         | 
| 336 | 
            -
            }
         | 
| 337 | 
            -
             | 
| 338 | 
            -
            #if defined(OJ_USE_SSE4_2)
         | 
| 339 | 
            -
            #include <nmmintrin.h>
         | 
| 340 | 
            -
             | 
| 341 | 
            -
            static inline void scan_string_SIMD(ParseInfo pi) {
         | 
| 342 | 
            -
                static const char chars[16] = "\x00\\\"";
         | 
| 343 | 
            -
                const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
         | 
| 344 | 
            -
                const char *end = (const char *)(pi->end - 16);
         | 
| 345 | 
            -
             | 
| 346 | 
            -
                for (; pi->cur <= end; pi->cur += 16) {
         | 
| 347 | 
            -
                    const __m128i string = _mm_loadu_si128((const __m128i *)pi->cur);
         | 
| 348 | 
            -
                    const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
         | 
| 349 | 
            -
                    if (r != 16) {
         | 
| 350 | 
            -
                        pi->cur = (const char*)(pi->cur + r);
         | 
| 351 | 
            -
                        return;
         | 
| 352 | 
            -
                    }
         | 
| 353 | 
            -
                }
         | 
| 354 | 
            -
             | 
| 355 | 
            -
                scan_string_noSIMD(pi);
         | 
| 356 | 
            -
            }
         | 
| 357 | 
            -
            #endif
         | 
| 358 | 
            -
             | 
| 359 402 | 
             
            static void read_str(ParseInfo pi) {
         | 
| 360 403 | 
             
                const char *str    = pi->cur;
         | 
| 361 404 | 
             
                Val         parent = stack_peek(&pi->stack);
         | 
| 362 405 |  | 
| 363 | 
            -
             | 
| 364 | 
            -
                scan_string_SIMD(pi);
         | 
| 365 | 
            -
            #else
         | 
| 366 | 
            -
                scan_string_noSIMD(pi);
         | 
| 367 | 
            -
            #endif
         | 
| 406 | 
            +
                pi->cur = scan_func(pi->cur, pi->end);
         | 
| 368 407 | 
             
                if (RB_UNLIKELY(pi->end <= pi->cur)) {
         | 
| 369 408 | 
             
                    oj_set_error_at(pi,
         | 
| 370 409 | 
             
                                    oj_parse_error_class,
         | 
| @@ -494,33 +533,31 @@ static void read_num(ParseInfo pi) { | |
| 494 533 | 
             
                    int  dec_cnt = 0;
         | 
| 495 534 | 
             
                    bool zero1   = false;
         | 
| 496 535 |  | 
| 536 | 
            +
                    // Skip leading zeros.
         | 
| 537 | 
            +
                    for (; '0' == *pi->cur; pi->cur++) {
         | 
| 538 | 
            +
                        zero1 = true;
         | 
| 539 | 
            +
                    }
         | 
| 540 | 
            +
             | 
| 497 541 | 
             
                    for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
         | 
| 498 | 
            -
                         | 
| 499 | 
            -
                            zero1 = true;
         | 
| 500 | 
            -
                        }
         | 
| 501 | 
            -
                        if (0 < ni.i) {
         | 
| 502 | 
            -
                            dec_cnt++;
         | 
| 503 | 
            -
                        }
         | 
| 504 | 
            -
                        if (!ni.big) {
         | 
| 505 | 
            -
                            int d = (*pi->cur - '0');
         | 
| 542 | 
            +
                        int d = (*pi->cur - '0');
         | 
| 506 543 |  | 
| 507 | 
            -
             | 
| 508 | 
            -
             | 
| 509 | 
            -
                                    oj_set_error_at(pi,
         | 
| 510 | 
            -
                                                    oj_parse_error_class,
         | 
| 511 | 
            -
                                                    __FILE__,
         | 
| 512 | 
            -
                                                    __LINE__,
         | 
| 513 | 
            -
                                                    "not a number");
         | 
| 514 | 
            -
                                    return;
         | 
| 515 | 
            -
                                }
         | 
| 516 | 
            -
                                zero1 = false;
         | 
| 517 | 
            -
                            }
         | 
| 518 | 
            -
                            ni.i = ni.i * 10 + d;
         | 
| 519 | 
            -
                            if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
         | 
| 520 | 
            -
                                ni.big = 1;
         | 
| 521 | 
            -
                            }
         | 
| 544 | 
            +
                        if (RB_LIKELY(0 != ni.i)) {
         | 
| 545 | 
            +
                            dec_cnt++;
         | 
| 522 546 | 
             
                        }
         | 
| 547 | 
            +
                        ni.i = ni.i * 10 + d;
         | 
| 548 | 
            +
                    }
         | 
| 549 | 
            +
                    if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
         | 
| 550 | 
            +
                        oj_set_error_at(pi,
         | 
| 551 | 
            +
                                        oj_parse_error_class,
         | 
| 552 | 
            +
                                        __FILE__,
         | 
| 553 | 
            +
                                        __LINE__,
         | 
| 554 | 
            +
                                        "not a number");
         | 
| 555 | 
            +
                        return;
         | 
| 556 | 
            +
                    }
         | 
| 557 | 
            +
                    if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
         | 
| 558 | 
            +
                        ni.big = true;
         | 
| 523 559 | 
             
                    }
         | 
| 560 | 
            +
             | 
| 524 561 | 
             
                    if ('.' == *pi->cur) {
         | 
| 525 562 | 
             
                        pi->cur++;
         | 
| 526 563 | 
             
                        // A trailing . is not a valid decimal but if encountered allow it
         | 
| @@ -540,25 +577,20 @@ static void read_num(ParseInfo pi) { | |
| 540 577 | 
             
                        for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
         | 
| 541 578 | 
             
                            int d = (*pi->cur - '0');
         | 
| 542 579 |  | 
| 543 | 
            -
                            if (0  | 
| 580 | 
            +
                            if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
         | 
| 544 581 | 
             
                                dec_cnt++;
         | 
| 545 582 | 
             
                            }
         | 
| 546 | 
            -
                             | 
| 547 | 
            -
             | 
| 548 | 
            -
             | 
| 549 | 
            -
                                }
         | 
| 550 | 
            -
                            } else {
         | 
| 551 | 
            -
                                ni.num = ni.num * 10 + d;
         | 
| 552 | 
            -
                                ni.div *= 10;
         | 
| 553 | 
            -
                                ni.di++;
         | 
| 554 | 
            -
                                if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
         | 
| 555 | 
            -
                                    if (!ni.no_big) {
         | 
| 556 | 
            -
                                        ni.big = true;
         | 
| 557 | 
            -
                                    }
         | 
| 558 | 
            -
                                }
         | 
| 559 | 
            -
                            }
         | 
| 583 | 
            +
                            ni.num = ni.num * 10 + d;
         | 
| 584 | 
            +
                            ni.div *= 10;
         | 
| 585 | 
            +
                            ni.di++;
         | 
| 560 586 | 
             
                        }
         | 
| 561 587 | 
             
                    }
         | 
| 588 | 
            +
                    if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
         | 
| 589 | 
            +
                        if (!ni.no_big) {
         | 
| 590 | 
            +
                            ni.big = true;
         | 
| 591 | 
            +
                        }
         | 
| 592 | 
            +
                    }
         | 
| 593 | 
            +
             | 
| 562 594 | 
             
                    if ('e' == *pi->cur || 'E' == *pi->cur) {
         | 
| 563 595 | 
             
                        int eneg = 0;
         | 
| 564 596 |  | 
    
        data/ext/oj/parse.h
    CHANGED
    
    
    
        data/ext/oj/parser.c
    CHANGED
    
    | @@ -533,6 +533,7 @@ static void calc_num(ojParser p) { | |
| 533 533 | 
             
                    // nothing to do
         | 
| 534 534 | 
             
                    break;
         | 
| 535 535 | 
             
                }
         | 
| 536 | 
            +
                p->type = OJ_NONE;
         | 
| 536 537 | 
             
            }
         | 
| 537 538 |  | 
| 538 539 | 
             
            static void big_change(ojParser p) {
         | 
| @@ -598,6 +599,8 @@ static void parse(ojParser p, const byte *json) { | |
| 598 599 | 
             
                const byte *b = json;
         | 
| 599 600 | 
             
                int         i;
         | 
| 600 601 |  | 
| 602 | 
            +
                p->line = 1;
         | 
| 603 | 
            +
                p->col  = -1;
         | 
| 601 604 | 
             
            #if DEBUG
         | 
| 602 605 | 
             
                printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
         | 
| 603 606 | 
             
            #endif
         | 
| @@ -652,6 +655,7 @@ static void parse(ojParser p, const byte *json) { | |
| 652 655 | 
             
                        }
         | 
| 653 656 | 
             
                        buf_append_string(&p->buf, (const char *)start, b - start);
         | 
| 654 657 | 
             
                        if ('"' == *b) {
         | 
| 658 | 
            +
                            p->cur = b - json;
         | 
| 655 659 | 
             
                            p->funcs[p->stack[p->depth]].add_str(p);
         | 
| 656 660 | 
             
                            p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 657 661 | 
             
                            break;
         | 
| @@ -661,12 +665,14 @@ static void parse(ojParser p, const byte *json) { | |
| 661 665 | 
             
                        p->next_map = (0 == p->depth) ? value_map : after_map;
         | 
| 662 666 | 
             
                        break;
         | 
| 663 667 | 
             
                    case OPEN_OBJECT:
         | 
| 668 | 
            +
                        p->cur = b - json;
         | 
| 664 669 | 
             
                        p->funcs[p->stack[p->depth]].open_object(p);
         | 
| 665 670 | 
             
                        p->depth++;
         | 
| 666 671 | 
             
                        p->stack[p->depth] = OBJECT_FUN;
         | 
| 667 672 | 
             
                        p->map             = key1_map;
         | 
| 668 673 | 
             
                        break;
         | 
| 669 674 | 
             
                    case NUM_CLOSE_OBJECT:
         | 
| 675 | 
            +
                        p->cur = b - json;
         | 
| 670 676 | 
             
                        calc_num(p);
         | 
| 671 677 | 
             
                        // flow through
         | 
| 672 678 | 
             
                    case CLOSE_OBJECT:
         | 
| @@ -677,15 +683,18 @@ static void parse(ojParser p, const byte *json) { | |
| 677 683 | 
             
                            return;
         | 
| 678 684 | 
             
                        }
         | 
| 679 685 | 
             
                        p->depth--;
         | 
| 686 | 
            +
                        p->cur = b - json;
         | 
| 680 687 | 
             
                        p->funcs[p->stack[p->depth]].close_object(p);
         | 
| 681 688 | 
             
                        break;
         | 
| 682 689 | 
             
                    case OPEN_ARRAY:
         | 
| 690 | 
            +
                        p->cur = b - json;
         | 
| 683 691 | 
             
                        p->funcs[p->stack[p->depth]].open_array(p);
         | 
| 684 692 | 
             
                        p->depth++;
         | 
| 685 693 | 
             
                        p->stack[p->depth] = ARRAY_FUN;
         | 
| 686 694 | 
             
                        p->map             = value_map;
         | 
| 687 695 | 
             
                        break;
         | 
| 688 696 | 
             
                    case NUM_CLOSE_ARRAY:
         | 
| 697 | 
            +
                        p->cur = b - json;
         | 
| 689 698 | 
             
                        calc_num(p);
         | 
| 690 699 | 
             
                        // flow through
         | 
| 691 700 | 
             
                    case CLOSE_ARRAY:
         | 
| @@ -696,9 +705,11 @@ static void parse(ojParser p, const byte *json) { | |
| 696 705 | 
             
                            return;
         | 
| 697 706 | 
             
                        }
         | 
| 698 707 | 
             
                        p->depth--;
         | 
| 708 | 
            +
                        p->cur = b - json;
         | 
| 699 709 | 
             
                        p->funcs[p->stack[p->depth]].close_array(p);
         | 
| 700 710 | 
             
                        break;
         | 
| 701 711 | 
             
                    case NUM_COMMA:
         | 
| 712 | 
            +
                        p->cur = b - json;
         | 
| 702 713 | 
             
                        calc_num(p);
         | 
| 703 714 | 
             
                        if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
         | 
| 704 715 | 
             
                            p->map = key_map;
         | 
| @@ -860,8 +871,14 @@ static void parse(ojParser p, const byte *json) { | |
| 860 871 | 
             
                        b--;
         | 
| 861 872 | 
             
                        p->map = big_exp_map;
         | 
| 862 873 | 
             
                        break;
         | 
| 863 | 
            -
                    case NUM_SPC: | 
| 864 | 
            -
             | 
| 874 | 
            +
                    case NUM_SPC:
         | 
| 875 | 
            +
                        p->cur = b - json;
         | 
| 876 | 
            +
                        calc_num(p);
         | 
| 877 | 
            +
                        break;
         | 
| 878 | 
            +
                    case NUM_NEWLINE:
         | 
| 879 | 
            +
                        p->cur = b - json;
         | 
| 880 | 
            +
                        calc_num(p);
         | 
| 881 | 
            +
                        b++;
         | 
| 865 882 | 
             
            #ifdef SPACE_JUMP
         | 
| 866 883 | 
             
                        // for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
         | 
| 867 884 | 
             
                        for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
         | 
| @@ -882,6 +899,7 @@ static void parse(ojParser p, const byte *json) { | |
| 882 899 | 
             
                            buf_append_string(&p->buf, (const char *)start, b - start);
         | 
| 883 900 | 
             
                        }
         | 
| 884 901 | 
             
                        if ('"' == *b) {
         | 
| 902 | 
            +
                            p->cur = b - json;
         | 
| 885 903 | 
             
                            p->funcs[p->stack[p->depth]].add_str(p);
         | 
| 886 904 | 
             
                            p->map = p->next_map;
         | 
| 887 905 | 
             
                            break;
         | 
| @@ -890,6 +908,7 @@ static void parse(ojParser p, const byte *json) { | |
| 890 908 | 
             
                        break;
         | 
| 891 909 | 
             
                    case STR_SLASH: p->map = esc_map; break;
         | 
| 892 910 | 
             
                    case STR_QUOTE:
         | 
| 911 | 
            +
                        p->cur = b - json;
         | 
| 893 912 | 
             
                        p->funcs[p->stack[p->depth]].add_str(p);
         | 
| 894 913 | 
             
                        p->map = p->next_map;
         | 
| 895 914 | 
             
                        break;
         | 
| @@ -967,6 +986,7 @@ static void parse(ojParser p, const byte *json) { | |
| 967 986 | 
             
                    case VAL_NULL:
         | 
| 968 987 | 
             
                        if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
         | 
| 969 988 | 
             
                            b += 3;
         | 
| 989 | 
            +
                            p->cur = b - json;
         | 
| 970 990 | 
             
                            p->funcs[p->stack[p->depth]].add_null(p);
         | 
| 971 991 | 
             
                            p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 972 992 | 
             
                            break;
         | 
| @@ -992,6 +1012,7 @@ static void parse(ojParser p, const byte *json) { | |
| 992 1012 | 
             
                    case VAL_TRUE:
         | 
| 993 1013 | 
             
                        if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
         | 
| 994 1014 | 
             
                            b += 3;
         | 
| 1015 | 
            +
                            p->cur = b - json;
         | 
| 995 1016 | 
             
                            p->funcs[p->stack[p->depth]].add_true(p);
         | 
| 996 1017 | 
             
                            p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 997 1018 | 
             
                            break;
         | 
| @@ -1017,6 +1038,7 @@ static void parse(ojParser p, const byte *json) { | |
| 1017 1038 | 
             
                    case VAL_FALSE:
         | 
| 1018 1039 | 
             
                        if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
         | 
| 1019 1040 | 
             
                            b += 4;
         | 
| 1041 | 
            +
                            p->cur = b - json;
         | 
| 1020 1042 | 
             
                            p->funcs[p->stack[p->depth]].add_false(p);
         | 
| 1021 1043 | 
             
                            p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 1022 1044 | 
             
                            break;
         | 
| @@ -1050,6 +1072,7 @@ static void parse(ojParser p, const byte *json) { | |
| 1050 1072 | 
             
                                    parse_error(p, "expected null");
         | 
| 1051 1073 | 
             
                                    return;
         | 
| 1052 1074 | 
             
                                }
         | 
| 1075 | 
            +
                                p->cur = b - json;
         | 
| 1053 1076 | 
             
                                p->funcs[p->stack[p->depth]].add_null(p);
         | 
| 1054 1077 | 
             
                                p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 1055 1078 | 
             
                            }
         | 
| @@ -1061,6 +1084,7 @@ static void parse(ojParser p, const byte *json) { | |
| 1061 1084 | 
             
                                    parse_error(p, "expected false");
         | 
| 1062 1085 | 
             
                                    return;
         | 
| 1063 1086 | 
             
                                }
         | 
| 1087 | 
            +
                                p->cur = b - json;
         | 
| 1064 1088 | 
             
                                p->funcs[p->stack[p->depth]].add_false(p);
         | 
| 1065 1089 | 
             
                                p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 1066 1090 | 
             
                            }
         | 
| @@ -1072,6 +1096,7 @@ static void parse(ojParser p, const byte *json) { | |
| 1072 1096 | 
             
                                    parse_error(p, "expected true");
         | 
| 1073 1097 | 
             
                                    return;
         | 
| 1074 1098 | 
             
                                }
         | 
| 1099 | 
            +
                                p->cur = b - json;
         | 
| 1075 1100 | 
             
                                p->funcs[p->stack[p->depth]].add_true(p);
         | 
| 1076 1101 | 
             
                                p->map = (0 == p->depth) ? value_map : after_map;
         | 
| 1077 1102 | 
             
                            }
         | 
| @@ -1089,6 +1114,9 @@ static void parse(ojParser p, const byte *json) { | |
| 1089 1114 | 
             
                        p->map = trail_map;
         | 
| 1090 1115 | 
             
                    }
         | 
| 1091 1116 | 
             
                }
         | 
| 1117 | 
            +
                if (0 < p->depth) {
         | 
| 1118 | 
            +
                    parse_error(p, "parse error, not closed");
         | 
| 1119 | 
            +
                }
         | 
| 1092 1120 | 
             
                if (0 == p->depth) {
         | 
| 1093 1121 | 
             
                    switch (p->map[256]) {
         | 
| 1094 1122 | 
             
                    case '0':
         | 
| @@ -1099,7 +1127,10 @@ static void parse(ojParser p, const byte *json) { | |
| 1099 1127 | 
             
                    case 'D':
         | 
| 1100 1128 | 
             
                    case 'g':
         | 
| 1101 1129 | 
             
                    case 'B':
         | 
| 1102 | 
            -
                    case 'Y': | 
| 1130 | 
            +
                    case 'Y':
         | 
| 1131 | 
            +
                        p->cur = b - json;
         | 
| 1132 | 
            +
                        calc_num(p);
         | 
| 1133 | 
            +
                        break;
         | 
| 1103 1134 | 
             
                    }
         | 
| 1104 1135 | 
             
                }
         | 
| 1105 1136 | 
             
                return;
         | 
| @@ -1456,7 +1487,7 @@ static VALUE saj_parser = Qundef; | |
| 1456 1487 | 
             
            /* Document-method: saj
         | 
| 1457 1488 | 
             
             * call-seq: saj
         | 
| 1458 1489 | 
             
             *
         | 
| 1459 | 
            -
             * Returns the default  | 
| 1490 | 
            +
             * Returns the default SAJ parser. Note the default SAJ parser can not be used
         | 
| 1460 1491 | 
             
             * concurrently in more than one thread.
         | 
| 1461 1492 | 
             
             */
         | 
| 1462 1493 | 
             
            static VALUE parser_saj(VALUE self) {
         | 
    
        data/ext/oj/parser.h
    CHANGED
    
    
    
        data/ext/oj/rails.c
    CHANGED
    
    | @@ -517,7 +517,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) { | |
| 517 517 | 
             
            static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
         | 
| 518 518 | 
             
                volatile VALUE ja;
         | 
| 519 519 |  | 
| 520 | 
            -
                if (Yes == out->opts->trace) {
         | 
| 520 | 
            +
                if (RB_UNLIKELY(Yes == out->opts->trace)) {
         | 
| 521 521 | 
             
                    oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
         | 
| 522 522 | 
             
                }
         | 
| 523 523 | 
             
                // Some classes elect to not take an options argument so check the arity
         | 
| @@ -527,7 +527,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) { | |
| 527 527 | 
             
                } else {
         | 
| 528 528 | 
             
                    ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
         | 
| 529 529 | 
             
                }
         | 
| 530 | 
            -
                if (Yes == out->opts->trace) {
         | 
| 530 | 
            +
                if (RB_UNLIKELY(Yes == out->opts->trace)) {
         | 
| 531 531 | 
             
                    oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
         | 
| 532 532 | 
             
                }
         | 
| 533 533 |  | 
| @@ -1464,7 +1464,7 @@ static DumpFunc rails_funcs[] = { | |
| 1464 1464 | 
             
            static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
         | 
| 1465 1465 | 
             
                int type = rb_type(obj);
         | 
| 1466 1466 |  | 
| 1467 | 
            -
                if (Yes == out->opts->trace) {
         | 
| 1467 | 
            +
                if (RB_UNLIKELY(Yes == out->opts->trace)) {
         | 
| 1468 1468 | 
             
                    oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
         | 
| 1469 1469 | 
             
                }
         | 
| 1470 1470 | 
             
                if (MAX_DEPTH < depth) {
         | 
| @@ -1475,14 +1475,14 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) { | |
| 1475 1475 |  | 
| 1476 1476 | 
             
                    if (NULL != f) {
         | 
| 1477 1477 | 
             
                        f(obj, depth, out, as_ok);
         | 
| 1478 | 
            -
                        if (Yes == out->opts->trace) {
         | 
| 1478 | 
            +
                        if (RB_UNLIKELY(Yes == out->opts->trace)) {
         | 
| 1479 1479 | 
             
                            oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
         | 
| 1480 1480 | 
             
                        }
         | 
| 1481 1481 | 
             
                        return;
         | 
| 1482 1482 | 
             
                    }
         | 
| 1483 1483 | 
             
                }
         | 
| 1484 1484 | 
             
                oj_dump_nil(Qnil, depth, out, false);
         | 
| 1485 | 
            -
                if (Yes == out->opts->trace) {
         | 
| 1485 | 
            +
                if (RB_UNLIKELY(Yes == out->opts->trace)) {
         | 
| 1486 1486 | 
             
                    oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
         | 
| 1487 1487 | 
             
                }
         | 
| 1488 1488 | 
             
            }
         |