oj 3.11.8 → 3.12.0
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/ext/oj/compat.c +23 -26
- data/ext/oj/custom.c +3 -15
- data/ext/oj/hash.c +16 -1
- data/ext/oj/hash.h +2 -0
- data/ext/oj/mimic_json.c +6 -4
- data/ext/oj/object.c +29 -1
- data/ext/oj/oj.c +43 -2
- data/ext/oj/oj.h +2 -0
- data/ext/oj/parse.h +3 -0
- data/ext/oj/scp.c +4 -16
- data/ext/oj/strict.c +67 -22
- data/ext/oj/wab.c +31 -21
- data/lib/oj/version.rb +1 -1
- data/test/perf.rb +1 -1
- data/test/perf_scp.rb +11 -10
- data/test/perf_strict.rb +17 -23
- data/test/test_various.rb +2 -0
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d5bf6799d9923c05b62b3bde88f052bb4373e9e0f15153f59e137b1023205a23
         | 
| 4 | 
            +
              data.tar.gz: 872155b5f53adb9a8dfbd20e54a9b1a329762c353b25b656eba071e85966acbd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5426970bd5c337bb387de75baa6589a82e81549d54b77c4ee7557fc52767cc933dcafb88b30e995ddf0c265ccd3e0d572c173bd4246d7c3998894879808aa68e
         | 
| 7 | 
            +
              data.tar.gz: d6748332981816586e67aa48b80f0730b7bfe13b124e0afea70fae323b8908b49dede05b39f80586a017391dc7d257ad889a2f828cedfdd0ccd272835f69e2a6
         | 
    
        data/ext/oj/compat.c
    CHANGED
    
    | @@ -23,14 +23,26 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c | |
| 23 23 | 
             
                    parent->classname = oj_strndup(str, len);
         | 
| 24 24 | 
             
                    parent->clen      = len;
         | 
| 25 25 | 
             
                } else {
         | 
| 26 | 
            -
                    volatile VALUE rstr =  | 
| 26 | 
            +
                    volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 27 27 |  | 
| 28 28 | 
             
                    if (Qundef == rkey) {
         | 
| 29 | 
            -
                         | 
| 30 | 
            -
             | 
| 31 | 
            -
                        rkey = oj_encode(rkey);
         | 
| 29 | 
            +
                        VALUE *slot;
         | 
| 30 | 
            +
             | 
| 32 31 | 
             
                        if (Yes == pi->options.sym_key) {
         | 
| 33 | 
            -
                            rkey =  | 
| 32 | 
            +
                            if (Qnil == (rkey = oj_sym_hash_get(key, klen, &slot))) {
         | 
| 33 | 
            +
                                rkey  = rb_str_new(key, klen);
         | 
| 34 | 
            +
                                rkey  = oj_encode(rkey);
         | 
| 35 | 
            +
                                rkey  = rb_str_intern(rkey);
         | 
| 36 | 
            +
                                *slot = rkey;
         | 
| 37 | 
            +
                                rb_gc_register_address(slot);
         | 
| 38 | 
            +
                            }
         | 
| 39 | 
            +
                        } else {
         | 
| 40 | 
            +
                            if (Qnil == (rkey = oj_str_hash_get(key, klen, &slot))) {
         | 
| 41 | 
            +
                                rkey  = rb_str_new(key, klen);
         | 
| 42 | 
            +
                                rkey  = oj_encode(rkey);
         | 
| 43 | 
            +
                                *slot = rkey;
         | 
| 44 | 
            +
                                rb_gc_register_address(slot);
         | 
| 45 | 
            +
                            }
         | 
| 34 46 | 
             
                        }
         | 
| 35 47 | 
             
                    }
         | 
| 36 48 | 
             
                    if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
         | 
| @@ -93,23 +105,9 @@ static void end_hash(struct _parseInfo *pi) { | |
| 93 105 | 
             
                }
         | 
| 94 106 | 
             
            }
         | 
| 95 107 |  | 
| 96 | 
            -
            static VALUE calc_hash_key(ParseInfo pi, Val parent) {
         | 
| 97 | 
            -
                volatile VALUE rkey = parent->key_val;
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                if (Qundef == rkey) {
         | 
| 100 | 
            -
                    rkey = rb_str_new(parent->key, parent->klen);
         | 
| 101 | 
            -
                }
         | 
| 102 | 
            -
                rkey = oj_encode(rkey);
         | 
| 103 | 
            -
                if (Yes == pi->options.sym_key) {
         | 
| 104 | 
            -
                    rkey = rb_str_intern(rkey);
         | 
| 105 | 
            -
                }
         | 
| 106 | 
            -
                return rkey;
         | 
| 107 | 
            -
            }
         | 
| 108 | 
            -
             | 
| 109 108 | 
             
            static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 110 | 
            -
                volatile VALUE rstr =  | 
| 109 | 
            +
                volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 111 110 |  | 
| 112 | 
            -
                rstr = oj_encode(rstr);
         | 
| 113 111 | 
             
                if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
         | 
| 114 112 | 
             
                    VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
         | 
| 115 113 |  | 
| @@ -142,10 +140,10 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) { | |
| 142 140 | 
             
                    rb_funcall(stack_peek(&pi->stack)->val,
         | 
| 143 141 | 
             
                               rb_intern("[]="),
         | 
| 144 142 | 
             
                               2,
         | 
| 145 | 
            -
                                | 
| 143 | 
            +
                               oj_calc_hash_key(pi, parent),
         | 
| 146 144 | 
             
                               rval);
         | 
| 147 145 | 
             
                } else {
         | 
| 148 | 
            -
                    rb_hash_aset(stack_peek(&pi->stack)->val,  | 
| 146 | 
            +
                    rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
         | 
| 149 147 | 
             
                }
         | 
| 150 148 | 
             
                if (Yes == pi->options.trace) {
         | 
| 151 149 | 
             
                    oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
         | 
| @@ -161,10 +159,10 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { | |
| 161 159 | 
             
                    rb_funcall(stack_peek(&pi->stack)->val,
         | 
| 162 160 | 
             
                               rb_intern("[]="),
         | 
| 163 161 | 
             
                               2,
         | 
| 164 | 
            -
                                | 
| 162 | 
            +
                               oj_calc_hash_key(pi, parent),
         | 
| 165 163 | 
             
                               value);
         | 
| 166 164 | 
             
                } else {
         | 
| 167 | 
            -
                    rb_hash_aset(stack_peek(&pi->stack)->val,  | 
| 165 | 
            +
                    rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
         | 
| 168 166 | 
             
                }
         | 
| 169 167 | 
             
                if (Yes == pi->options.trace) {
         | 
| 170 168 | 
             
                    oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
         | 
| @@ -199,9 +197,8 @@ static void array_append_num(ParseInfo pi, NumInfo ni) { | |
| 199 197 | 
             
            }
         | 
| 200 198 |  | 
| 201 199 | 
             
            static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 202 | 
            -
                volatile VALUE rstr =  | 
| 200 | 
            +
                volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 203 201 |  | 
| 204 | 
            -
                rstr = oj_encode(rstr);
         | 
| 205 202 | 
             
                if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
         | 
| 206 203 | 
             
                    VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
         | 
| 207 204 |  | 
    
        data/ext/oj/custom.c
    CHANGED
    
    | @@ -955,6 +955,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c | |
| 955 955 | 
             
                        }
         | 
| 956 956 | 
             
                    }
         | 
| 957 957 | 
             
                } else {
         | 
| 958 | 
            +
            	//volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 958 959 | 
             
                    volatile VALUE rstr = rb_str_new(str, len);
         | 
| 959 960 |  | 
| 960 961 | 
             
                    if (Qundef == rkey) {
         | 
| @@ -1010,19 +1011,6 @@ static void end_hash(struct _parseInfo *pi) { | |
| 1010 1011 | 
             
                }
         | 
| 1011 1012 | 
             
            }
         | 
| 1012 1013 |  | 
| 1013 | 
            -
            static VALUE calc_hash_key(ParseInfo pi, Val parent) {
         | 
| 1014 | 
            -
                volatile VALUE rkey = parent->key_val;
         | 
| 1015 | 
            -
             | 
| 1016 | 
            -
                if (Qundef == rkey) {
         | 
| 1017 | 
            -
                    rkey = rb_str_new(parent->key, parent->klen);
         | 
| 1018 | 
            -
                }
         | 
| 1019 | 
            -
                rkey = oj_encode(rkey);
         | 
| 1020 | 
            -
                if (Yes == pi->options.sym_key) {
         | 
| 1021 | 
            -
                    rkey = rb_str_intern(rkey);
         | 
| 1022 | 
            -
                }
         | 
| 1023 | 
            -
                return rkey;
         | 
| 1024 | 
            -
            }
         | 
| 1025 | 
            -
             | 
| 1026 1014 | 
             
            static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
         | 
| 1027 1015 | 
             
                Val            parent = stack_peek(&pi->stack);
         | 
| 1028 1016 | 
             
                volatile VALUE rval   = oj_num_as_value(ni);
         | 
| @@ -1067,7 +1055,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) { | |
| 1067 1055 | 
             
                        }
         | 
| 1068 1056 | 
             
                        rval = parent->val;
         | 
| 1069 1057 | 
             
                    } else {
         | 
| 1070 | 
            -
                        rb_hash_aset(parent->val,  | 
| 1058 | 
            +
                        rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), rval);
         | 
| 1071 1059 | 
             
                    }
         | 
| 1072 1060 | 
             
                    break;
         | 
| 1073 1061 | 
             
                default: break;
         | 
| @@ -1082,7 +1070,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { | |
| 1082 1070 |  | 
| 1083 1071 | 
             
                switch (rb_type(parent->val)) {
         | 
| 1084 1072 | 
             
                case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
         | 
| 1085 | 
            -
                case T_HASH: rb_hash_aset(parent->val,  | 
| 1073 | 
            +
                case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
         | 
| 1086 1074 | 
             
                default: break;
         | 
| 1087 1075 | 
             
                }
         | 
| 1088 1076 | 
             
                if (Yes == pi->options.trace) {
         | 
    
        data/ext/oj/hash.c
    CHANGED
    
    | @@ -20,6 +20,8 @@ struct _hash { | |
| 20 20 | 
             
            };
         | 
| 21 21 |  | 
| 22 22 | 
             
            struct _hash class_hash;
         | 
| 23 | 
            +
            struct _hash str_hash;
         | 
| 24 | 
            +
            struct _hash sym_hash;
         | 
| 23 25 | 
             
            struct _hash intern_hash;
         | 
| 24 26 |  | 
| 25 27 | 
             
            // almost the Murmur hash algorithm
         | 
| @@ -64,6 +66,8 @@ static uint32_t hash_calc(const uint8_t *key, size_t len) { | |
| 64 66 |  | 
| 65 67 | 
             
            void oj_hash_init() {
         | 
| 66 68 | 
             
                memset(class_hash.slots, 0, sizeof(class_hash.slots));
         | 
| 69 | 
            +
                memset(str_hash.slots, 0, sizeof(str_hash.slots));
         | 
| 70 | 
            +
                memset(sym_hash.slots, 0, sizeof(sym_hash.slots));
         | 
| 67 71 | 
             
                memset(intern_hash.slots, 0, sizeof(intern_hash.slots));
         | 
| 68 72 | 
             
            }
         | 
| 69 73 |  | 
| @@ -117,7 +121,18 @@ oj_class_hash_get(const char *key, size_t len, VALUE **slotp) { | |
| 117 121 | 
             
                return hash_get(&class_hash, key, len, slotp, Qnil);
         | 
| 118 122 | 
             
            }
         | 
| 119 123 |  | 
| 120 | 
            -
             | 
| 124 | 
            +
            VALUE
         | 
| 125 | 
            +
            oj_str_hash_get(const char *key, size_t len, VALUE **slotp) {
         | 
| 126 | 
            +
                return hash_get(&str_hash, key, len, slotp, Qnil);
         | 
| 127 | 
            +
            }
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            VALUE
         | 
| 130 | 
            +
            oj_sym_hash_get(const char *key, size_t len, VALUE **slotp) {
         | 
| 131 | 
            +
                return hash_get(&sym_hash, key, len, slotp, Qnil);
         | 
| 132 | 
            +
            }
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            ID
         | 
| 135 | 
            +
            oj_attr_hash_get(const char *key, size_t len, ID **slotp) {
         | 
| 121 136 | 
             
                return (ID)hash_get(&intern_hash, key, len, (VALUE **)slotp, 0);
         | 
| 122 137 | 
             
            }
         | 
| 123 138 |  | 
    
        data/ext/oj/hash.h
    CHANGED
    
    | @@ -11,6 +11,8 @@ typedef struct _hash *Hash; | |
| 11 11 | 
             
            extern void oj_hash_init();
         | 
| 12 12 |  | 
| 13 13 | 
             
            extern VALUE oj_class_hash_get(const char *key, size_t len, VALUE **slotp);
         | 
| 14 | 
            +
            extern VALUE oj_str_hash_get(const char *key, size_t len, VALUE **slotp);
         | 
| 15 | 
            +
            extern VALUE oj_sym_hash_get(const char *key, size_t len, VALUE **slotp);
         | 
| 14 16 | 
             
            extern ID    oj_attr_hash_get(const char *key, size_t len, ID **slotp);
         | 
| 15 17 |  | 
| 16 18 | 
             
            extern void  oj_hash_print();
         | 
    
        data/ext/oj/mimic_json.c
    CHANGED
    
    | @@ -389,9 +389,9 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) { | |
| 389 389 | 
             
                } else {
         | 
| 390 390 | 
             
                    VALUE active_hack[1];
         | 
| 391 391 |  | 
| 392 | 
            -
             | 
| 393 | 
            -
             | 
| 394 | 
            -
             | 
| 392 | 
            +
                    if (Qundef == state_class) {
         | 
| 393 | 
            +
                        oj_define_mimic_json(0, NULL, Qnil);
         | 
| 394 | 
            +
                    }
         | 
| 395 395 | 
             
                    active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
         | 
| 396 396 | 
             
                    oj_dump_obj_to_json_using_params(*argv, copts, &out, 1, active_hack);
         | 
| 397 397 | 
             
                }
         | 
| @@ -480,7 +480,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) { | |
| 480 480 | 
             
                    rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
         | 
| 481 481 | 
             
                }
         | 
| 482 482 | 
             
                if (Qundef == state_class) {
         | 
| 483 | 
            -
             | 
| 483 | 
            +
                    oj_define_mimic_json(0, NULL, Qnil);
         | 
| 484 484 | 
             
                }
         | 
| 485 485 | 
             
                rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
         | 
| 486 486 |  | 
| @@ -713,6 +713,8 @@ static struct _options mimic_object_to_json_options = {0,              // indent | |
| 713 713 | 
             
                                                                   No,             // safe
         | 
| 714 714 | 
             
                                                                   false,          // sec_prec_set
         | 
| 715 715 | 
             
                                                                   No,             // ignore_under
         | 
| 716 | 
            +
                                                                   Yes,            // cache_keys
         | 
| 717 | 
            +
                                                                   3,              // cache_str
         | 
| 716 718 | 
             
                                                                   0,              // int_range_min
         | 
| 717 719 | 
             
                                                                   0,              // int_range_max
         | 
| 718 720 | 
             
                                                                   oj_json_class,  // create_id
         | 
    
        data/ext/oj/object.c
    CHANGED
    
    | @@ -30,11 +30,38 @@ inline static long read_long(const char *str, size_t len) { | |
| 30 30 |  | 
| 31 31 | 
             
            static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
         | 
| 32 32 | 
             
                volatile VALUE rkey;
         | 
| 33 | 
            +
            #if 0
         | 
| 34 | 
            +
                VALUE *slot;
         | 
| 33 35 |  | 
| 36 | 
            +
                if (':' == k1) {
         | 
| 37 | 
            +
                    if (Qnil == (rkey = oj_sym_hash_get(kval->key + 1, kval->klen - 1, &slot))) {
         | 
| 38 | 
            +
                        rkey  = rb_str_new(kval->key + 1, kval->klen - 1);
         | 
| 39 | 
            +
                        rkey  = oj_encode(rkey);
         | 
| 40 | 
            +
                        rkey  = rb_str_intern(rkey);
         | 
| 41 | 
            +
                        *slot = rkey;
         | 
| 42 | 
            +
                        rb_gc_register_address(slot);
         | 
| 43 | 
            +
                    }
         | 
| 44 | 
            +
                } else if (Yes == pi->options.sym_key) {
         | 
| 45 | 
            +
                    if (Qnil == (rkey = oj_sym_hash_get(kval->key, kval->klen, &slot))) {
         | 
| 46 | 
            +
                        rkey  = rb_str_new(kval->key, kval->klen);
         | 
| 47 | 
            +
                        rkey  = oj_encode(rkey);
         | 
| 48 | 
            +
                        rkey  = rb_str_intern(rkey);
         | 
| 49 | 
            +
                        *slot = rkey;
         | 
| 50 | 
            +
                        rb_gc_register_address(slot);
         | 
| 51 | 
            +
                    }
         | 
| 52 | 
            +
                } else {
         | 
| 53 | 
            +
                    if (Qnil == (rkey = oj_str_hash_get(kval->key, kval->klen, &slot))) {
         | 
| 54 | 
            +
                        rkey  = rb_str_new(kval->key, kval->klen);
         | 
| 55 | 
            +
                        rkey  = oj_encode(rkey);
         | 
| 56 | 
            +
                        *slot = rkey;
         | 
| 57 | 
            +
                        rb_gc_register_address(slot);
         | 
| 58 | 
            +
                    }
         | 
| 59 | 
            +
                }
         | 
| 60 | 
            +
            #else
         | 
| 34 61 | 
             
                if (':' == k1) {
         | 
| 35 62 | 
             
                    rkey = rb_str_new(kval->key + 1, kval->klen - 1);
         | 
| 36 63 | 
             
                    rkey = oj_encode(rkey);
         | 
| 37 | 
            -
             | 
| 64 | 
            +
            	rkey  = rb_str_intern(rkey);
         | 
| 38 65 | 
             
                } else {
         | 
| 39 66 | 
             
                    rkey = rb_str_new(kval->key, kval->klen);
         | 
| 40 67 | 
             
                    rkey = oj_encode(rkey);
         | 
| @@ -42,6 +69,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) { | |
| 42 69 | 
             
                        rkey = rb_str_intern(rkey);
         | 
| 43 70 | 
             
                    }
         | 
| 44 71 | 
             
                }
         | 
| 72 | 
            +
            #endif
         | 
| 45 73 | 
             
                return rkey;
         | 
| 46 74 | 
             
            }
         | 
| 47 75 |  | 
    
        data/ext/oj/oj.c
    CHANGED
    
    | @@ -106,6 +106,8 @@ static VALUE auto_sym; | |
| 106 106 | 
             
            static VALUE bigdecimal_as_decimal_sym;
         | 
| 107 107 | 
             
            static VALUE bigdecimal_load_sym;
         | 
| 108 108 | 
             
            static VALUE bigdecimal_sym;
         | 
| 109 | 
            +
            static VALUE cache_keys_sym;
         | 
| 110 | 
            +
            static VALUE cache_str_sym;
         | 
| 109 111 | 
             
            static VALUE circular_sym;
         | 
| 110 112 | 
             
            static VALUE class_cache_sym;
         | 
| 111 113 | 
             
            static VALUE compat_bigdecimal_sym;
         | 
| @@ -186,6 +188,8 @@ struct _options oj_default_options = { | |
| 186 188 | 
             
                No,             // safe
         | 
| 187 189 | 
             
                false,          // sec_prec_set
         | 
| 188 190 | 
             
                No,             // ignore_under
         | 
| 191 | 
            +
                Yes,            // cache_keys
         | 
| 192 | 
            +
                3,              // cache_str
         | 
| 189 193 | 
             
                0,              // int_range_min
         | 
| 190 194 | 
             
                0,              // int_range_max
         | 
| 191 195 | 
             
                oj_json_class,  // create_id
         | 
| @@ -279,9 +283,11 @@ struct _options oj_default_options = { | |
| 279 283 | 
             
             *used
         | 
| 280 284 | 
             
             * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
         | 
| 281 285 | 
             
             * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
         | 
| 282 | 
            -
             * - *:ignore* [_nil_| | 
| 283 | 
            -
             * - *:ignore_under* [ | 
| 286 | 
            +
             * - *:ignore* [_nil_|_Array_] either nil or an Array of classes to ignore when dumping
         | 
| 287 | 
            +
             * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when dumping in
         | 
| 284 288 | 
             
             *object or custom mode.
         | 
| 289 | 
            +
             * - *:cache_keys* [_Boolean_] if true then hash keys are cached
         | 
| 290 | 
            +
             * - *:cache_str* [_Fixnum_] maximum string value length to cache
         | 
| 285 291 | 
             
             * - *:integer_range* [_Range_] Dump integers outside range as strings.
         | 
| 286 292 | 
             
             * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
         | 
| 287 293 | 
             
             * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is
         | 
| @@ -389,11 +395,17 @@ static VALUE get_def_opts(VALUE self) { | |
| 389 395 | 
             
                                 ? Qtrue
         | 
| 390 396 | 
             
                                 : ((No == oj_default_options.safe) ? Qfalse : Qnil));
         | 
| 391 397 | 
             
                rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
         | 
| 398 | 
            +
                rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str));
         | 
| 392 399 | 
             
                rb_hash_aset(opts,
         | 
| 393 400 | 
             
                             ignore_under_sym,
         | 
| 394 401 | 
             
                             (Yes == oj_default_options.ignore_under)
         | 
| 395 402 | 
             
                                 ? Qtrue
         | 
| 396 403 | 
             
                                 : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
         | 
| 404 | 
            +
                rb_hash_aset(opts,
         | 
| 405 | 
            +
                             cache_keys_sym,
         | 
| 406 | 
            +
                             (Yes == oj_default_options.cache_keys)
         | 
| 407 | 
            +
                                 ? Qtrue
         | 
| 408 | 
            +
                                 : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
         | 
| 397 409 | 
             
                switch (oj_default_options.mode) {
         | 
| 398 410 | 
             
                case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
         | 
| 399 411 | 
             
                case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
         | 
| @@ -557,6 +569,8 @@ static VALUE get_def_opts(VALUE self) { | |
| 557 569 | 
             
             *   - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
         | 
| 558 570 | 
             
             *   - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when
         | 
| 559 571 | 
             
             *dumping in object or custom mode.
         | 
| 572 | 
            +
             *   - *:cache_keys* [_Boolean_] if true then hash keys are cached
         | 
| 573 | 
            +
             *   - *:cache_str* [_Fixnum_] maximum string vsalue length to cache
         | 
| 560 574 | 
             
             *   - *:integer_range* [_Range_] Dump integers outside range as strings.
         | 
| 561 575 | 
             
             *   - *:trace* [_Boolean_] turn trace on or off.
         | 
| 562 576 | 
             
             *   - *:safe* [_Boolean_] turn safe mimic on or off.
         | 
| @@ -589,6 +603,7 @@ void oj_parse_options(VALUE ropts, Options copts) { | |
| 589 603 | 
             
                                           {oj_safe_sym, &copts->safe},
         | 
| 590 604 | 
             
                                           {ignore_under_sym, &copts->ignore_under},
         | 
| 591 605 | 
             
                                           {oj_create_additions_sym, &copts->create_ok},
         | 
| 606 | 
            +
                                           {cache_keys_sym, &copts->cache_keys},
         | 
| 592 607 | 
             
                                           {Qnil, 0}};
         | 
| 593 608 | 
             
                YesNoOpt         o;
         | 
| 594 609 | 
             
                volatile VALUE   v;
         | 
| @@ -647,6 +662,28 @@ void oj_parse_options(VALUE ropts, Options copts) { | |
| 647 662 | 
             
                        copts->float_prec = n;
         | 
| 648 663 | 
             
                    }
         | 
| 649 664 | 
             
                }
         | 
| 665 | 
            +
                if (Qnil != (v = rb_hash_lookup(ropts, cache_str_sym))) {
         | 
| 666 | 
            +
                    int n;
         | 
| 667 | 
            +
             | 
| 668 | 
            +
            #ifdef RUBY_INTEGER_UNIFICATION
         | 
| 669 | 
            +
                    if (rb_cInteger != rb_obj_class(v)) {
         | 
| 670 | 
            +
                        rb_raise(rb_eArgError, ":cache_str must be a Integer.");
         | 
| 671 | 
            +
                    }
         | 
| 672 | 
            +
            #else
         | 
| 673 | 
            +
                    if (T_FIXNUM != rb_type(v)) {
         | 
| 674 | 
            +
                        rb_raise(rb_eArgError, ":cache_str must be a Fixnum.");
         | 
| 675 | 
            +
                    }
         | 
| 676 | 
            +
            #endif
         | 
| 677 | 
            +
                    n = FIX2INT(v);
         | 
| 678 | 
            +
                    if (0 >= n) {
         | 
| 679 | 
            +
                        copts->cache_str = 0;
         | 
| 680 | 
            +
                    } else {
         | 
| 681 | 
            +
                        if (32 < n) {
         | 
| 682 | 
            +
                            n = 32;
         | 
| 683 | 
            +
                        }
         | 
| 684 | 
            +
                        copts->cache_str = (char)n;
         | 
| 685 | 
            +
                    }
         | 
| 686 | 
            +
                }
         | 
| 650 687 | 
             
                if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
         | 
| 651 688 | 
             
                    int n;
         | 
| 652 689 |  | 
| @@ -1816,6 +1853,10 @@ void Init_oj() { | |
| 1816 1853 | 
             
                rb_gc_register_address(&bigdecimal_load_sym);
         | 
| 1817 1854 | 
             
                bigdecimal_sym = ID2SYM(rb_intern("bigdecimal"));
         | 
| 1818 1855 | 
             
                rb_gc_register_address(&bigdecimal_sym);
         | 
| 1856 | 
            +
                cache_keys_sym = ID2SYM(rb_intern("cache_keys"));
         | 
| 1857 | 
            +
                rb_gc_register_address(&cache_keys_sym);
         | 
| 1858 | 
            +
                cache_str_sym = ID2SYM(rb_intern("cache_str"));
         | 
| 1859 | 
            +
                rb_gc_register_address(&cache_str_sym);
         | 
| 1819 1860 | 
             
                circular_sym = ID2SYM(rb_intern("circular"));
         | 
| 1820 1861 | 
             
                rb_gc_register_address(&circular_sym);
         | 
| 1821 1862 | 
             
                class_cache_sym = ID2SYM(rb_intern("class_cache"));
         | 
    
        data/ext/oj/oj.h
    CHANGED
    
    | @@ -143,6 +143,8 @@ typedef struct _options { | |
| 143 143 | 
             
                char safe;           // YesNo
         | 
| 144 144 | 
             
                char sec_prec_set;   // boolean (0 or 1)
         | 
| 145 145 | 
             
                char ignore_under;   // YesNo - ignore attrs starting with _ if true in object and custom modes
         | 
| 146 | 
            +
                char cache_keys;     // YexNo
         | 
| 147 | 
            +
                char cache_str;      // string short than or equal to this are cache
         | 
| 146 148 | 
             
                int64_t          int_range_min;  // dump numbers below as string
         | 
| 147 149 | 
             
                int64_t          int_range_max;  // dump numbers above as string
         | 
| 148 150 | 
             
                const char *     create_id;      // 0 or string
         | 
    
        data/ext/oj/parse.h
    CHANGED
    
    | @@ -90,6 +90,9 @@ extern void oj_set_wab_callbacks(ParseInfo pi); | |
| 90 90 | 
             
            extern void  oj_sparse2(ParseInfo pi);
         | 
| 91 91 | 
             
            extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd);
         | 
| 92 92 |  | 
| 93 | 
            +
            extern VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str);
         | 
| 94 | 
            +
            extern VALUE oj_calc_hash_key(ParseInfo pi, Val parent);
         | 
| 95 | 
            +
             | 
| 93 96 | 
             
            static inline void parse_info_init(ParseInfo pi) {
         | 
| 94 97 | 
             
                memset(pi, 0, sizeof(struct _parseInfo));
         | 
| 95 98 | 
             
            }
         | 
    
        data/ext/oj/scp.c
    CHANGED
    
    | @@ -9,6 +9,7 @@ | |
| 9 9 | 
             
            #include <unistd.h>
         | 
| 10 10 |  | 
| 11 11 | 
             
            #include "encode.h"
         | 
| 12 | 
            +
            #include "hash.h"
         | 
| 12 13 | 
             
            #include "oj.h"
         | 
| 13 14 | 
             
            #include "parse.h"
         | 
| 14 15 |  | 
| @@ -82,19 +83,6 @@ static void end_array(ParseInfo pi) { | |
| 82 83 | 
             
                rb_funcall(pi->handler, oj_array_end_id, 0);
         | 
| 83 84 | 
             
            }
         | 
| 84 85 |  | 
| 85 | 
            -
            static VALUE calc_hash_key(ParseInfo pi, Val kval) {
         | 
| 86 | 
            -
                volatile VALUE rkey = kval->key_val;
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                if (Qundef == rkey) {
         | 
| 89 | 
            -
                    rkey = rb_str_new(kval->key, kval->klen);
         | 
| 90 | 
            -
                    rkey = oj_encode(rkey);
         | 
| 91 | 
            -
                    if (Yes == pi->options.sym_key) {
         | 
| 92 | 
            -
                        rkey = rb_str_intern(rkey);
         | 
| 93 | 
            -
                    }
         | 
| 94 | 
            -
                }
         | 
| 95 | 
            -
                return rkey;
         | 
| 96 | 
            -
            }
         | 
| 97 | 
            -
             | 
| 98 86 | 
             
            static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
         | 
| 99 87 | 
             
                return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
         | 
| 100 88 | 
             
            }
         | 
| @@ -107,7 +95,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c | |
| 107 95 | 
             
                           oj_hash_set_id,
         | 
| 108 96 | 
             
                           3,
         | 
| 109 97 | 
             
                           stack_peek(&pi->stack)->val,
         | 
| 110 | 
            -
                            | 
| 98 | 
            +
                           oj_calc_hash_key(pi, kval),
         | 
| 111 99 | 
             
                           rstr);
         | 
| 112 100 | 
             
            }
         | 
| 113 101 |  | 
| @@ -116,7 +104,7 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) { | |
| 116 104 | 
             
                           oj_hash_set_id,
         | 
| 117 105 | 
             
                           3,
         | 
| 118 106 | 
             
                           stack_peek(&pi->stack)->val,
         | 
| 119 | 
            -
                            | 
| 107 | 
            +
                           oj_calc_hash_key(pi, kval),
         | 
| 120 108 | 
             
                           oj_num_as_value(ni));
         | 
| 121 109 | 
             
            }
         | 
| 122 110 |  | 
| @@ -125,7 +113,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { | |
| 125 113 | 
             
                           oj_hash_set_id,
         | 
| 126 114 | 
             
                           3,
         | 
| 127 115 | 
             
                           stack_peek(&pi->stack)->val,
         | 
| 128 | 
            -
                            | 
| 116 | 
            +
                           oj_calc_hash_key(pi, kval),
         | 
| 129 117 | 
             
                           value);
         | 
| 130 118 | 
             
            }
         | 
| 131 119 |  | 
    
        data/ext/oj/strict.c
    CHANGED
    
    | @@ -8,10 +8,65 @@ | |
| 8 8 |  | 
| 9 9 | 
             
            #include "encode.h"
         | 
| 10 10 | 
             
            #include "err.h"
         | 
| 11 | 
            +
            #include "hash.h"
         | 
| 11 12 | 
             
            #include "oj.h"
         | 
| 12 13 | 
             
            #include "parse.h"
         | 
| 13 14 | 
             
            #include "trace.h"
         | 
| 14 15 |  | 
| 16 | 
            +
            VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
         | 
| 17 | 
            +
                volatile VALUE rstr = Qnil;
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                if (len <= cache_str) {
         | 
| 20 | 
            +
                    VALUE *slot;
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) {
         | 
| 23 | 
            +
                        rstr  = rb_str_new(str, len);
         | 
| 24 | 
            +
                        rstr  = oj_encode(rstr);
         | 
| 25 | 
            +
                        *slot = rstr;
         | 
| 26 | 
            +
                        rb_gc_register_address(slot);
         | 
| 27 | 
            +
                    }
         | 
| 28 | 
            +
                } else {
         | 
| 29 | 
            +
                    rstr = rb_str_new(str, len);
         | 
| 30 | 
            +
                    rstr = oj_encode(rstr);
         | 
| 31 | 
            +
                }
         | 
| 32 | 
            +
                return rstr;
         | 
| 33 | 
            +
            }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
         | 
| 36 | 
            +
                volatile VALUE rkey = parent->key_val;
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                if (Qundef != rkey) {
         | 
| 39 | 
            +
                    return rkey;
         | 
| 40 | 
            +
                }
         | 
| 41 | 
            +
                if (Yes != pi->options.cache_keys) {
         | 
| 42 | 
            +
                    rkey = rb_str_new(parent->key, parent->klen);
         | 
| 43 | 
            +
                    rkey = oj_encode(rkey);
         | 
| 44 | 
            +
                    if (Yes == pi->options.sym_key) {
         | 
| 45 | 
            +
                        rkey = rb_str_intern(rkey);
         | 
| 46 | 
            +
                    }
         | 
| 47 | 
            +
                    return rkey;
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
                VALUE *slot;
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                if (Yes == pi->options.sym_key) {
         | 
| 52 | 
            +
                    if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
         | 
| 53 | 
            +
                        rkey  = rb_str_new(parent->key, parent->klen);
         | 
| 54 | 
            +
                        rkey  = oj_encode(rkey);
         | 
| 55 | 
            +
                        rkey  = rb_str_intern(rkey);
         | 
| 56 | 
            +
                        *slot = rkey;
         | 
| 57 | 
            +
                        rb_gc_register_address(slot);
         | 
| 58 | 
            +
                    }
         | 
| 59 | 
            +
                } else {
         | 
| 60 | 
            +
                    if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) {
         | 
| 61 | 
            +
                        rkey  = rb_str_new(parent->key, parent->klen);
         | 
| 62 | 
            +
                        rkey  = oj_encode(rkey);
         | 
| 63 | 
            +
                        *slot = rkey;
         | 
| 64 | 
            +
                        rb_gc_register_address(slot);
         | 
| 65 | 
            +
                    }
         | 
| 66 | 
            +
                }
         | 
| 67 | 
            +
                return rkey;
         | 
| 68 | 
            +
            }
         | 
| 69 | 
            +
             | 
| 15 70 | 
             
            static void hash_end(ParseInfo pi) {
         | 
| 16 71 | 
             
                if (Yes == pi->options.trace) {
         | 
| 17 72 | 
             
                    oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
         | 
| @@ -36,9 +91,8 @@ static void add_value(ParseInfo pi, VALUE val) { | |
| 36 91 | 
             
            }
         | 
| 37 92 |  | 
| 38 93 | 
             
            static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 39 | 
            -
                volatile VALUE rstr =  | 
| 94 | 
            +
                volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 40 95 |  | 
| 41 | 
            -
                rstr                = oj_encode(rstr);
         | 
| 42 96 | 
             
                pi->stack.head->val = rstr;
         | 
| 43 97 | 
             
                if (Yes == pi->options.trace) {
         | 
| 44 98 | 
             
                    oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
         | 
| @@ -65,24 +119,12 @@ static VALUE start_hash(ParseInfo pi) { | |
| 65 119 | 
             
                return rb_hash_new();
         | 
| 66 120 | 
             
            }
         | 
| 67 121 |  | 
| 68 | 
            -
            static VALUE calc_hash_key(ParseInfo pi, Val parent) {
         | 
| 69 | 
            -
                volatile VALUE rkey = parent->key_val;
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                if (Qundef == rkey) {
         | 
| 72 | 
            -
                    rkey = rb_str_new(parent->key, parent->klen);
         | 
| 73 | 
            -
                }
         | 
| 74 | 
            -
                rkey = oj_encode(rkey);
         | 
| 75 | 
            -
                if (Yes == pi->options.sym_key) {
         | 
| 76 | 
            -
                    rkey = rb_str_intern(rkey);
         | 
| 77 | 
            -
                }
         | 
| 78 | 
            -
                return rkey;
         | 
| 79 | 
            -
            }
         | 
| 80 | 
            -
             | 
| 81 122 | 
             
            static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
         | 
| 82 | 
            -
                volatile VALUE rstr =  | 
| 123 | 
            +
                volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 83 124 |  | 
| 84 | 
            -
                 | 
| 85 | 
            -
             | 
| 125 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val,
         | 
| 126 | 
            +
                             oj_calc_hash_key(pi, parent),
         | 
| 127 | 
            +
                             rstr);
         | 
| 86 128 | 
             
                if (Yes == pi->options.trace) {
         | 
| 87 129 | 
             
                    oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
         | 
| 88 130 | 
             
                }
         | 
| @@ -95,14 +137,18 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { | |
| 95 137 | 
             
                    oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
         | 
| 96 138 | 
             
                }
         | 
| 97 139 | 
             
                v = oj_num_as_value(ni);
         | 
| 98 | 
            -
                rb_hash_aset(stack_peek(&pi->stack)->val, | 
| 140 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val,
         | 
| 141 | 
            +
                             oj_calc_hash_key(pi, parent),
         | 
| 142 | 
            +
                             v);
         | 
| 99 143 | 
             
                if (Yes == pi->options.trace) {
         | 
| 100 144 | 
             
                    oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
         | 
| 101 145 | 
             
                }
         | 
| 102 146 | 
             
            }
         | 
| 103 147 |  | 
| 104 148 | 
             
            static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
         | 
| 105 | 
            -
                rb_hash_aset(stack_peek(&pi->stack)->val, | 
| 149 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val,
         | 
| 150 | 
            +
                             oj_calc_hash_key(pi, parent),
         | 
| 151 | 
            +
                             value);
         | 
| 106 152 | 
             
                if (Yes == pi->options.trace) {
         | 
| 107 153 | 
             
                    oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
         | 
| 108 154 | 
             
                }
         | 
| @@ -116,9 +162,8 @@ static VALUE start_array(ParseInfo pi) { | |
| 116 162 | 
             
            }
         | 
| 117 163 |  | 
| 118 164 | 
             
            static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 119 | 
            -
                volatile VALUE rstr =  | 
| 165 | 
            +
                volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 120 166 |  | 
| 121 | 
            -
                rstr = oj_encode(rstr);
         | 
| 122 167 | 
             
                rb_ary_push(stack_peek(&pi->stack)->val, rstr);
         | 
| 123 168 | 
             
                if (Yes == pi->options.trace) {
         | 
| 124 169 | 
             
                    oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
         | 
    
        data/ext/oj/wab.c
    CHANGED
    
    | @@ -10,6 +10,7 @@ | |
| 10 10 | 
             
            #include "dump.h"
         | 
| 11 11 | 
             
            #include "encode.h"
         | 
| 12 12 | 
             
            #include "err.h"
         | 
| 13 | 
            +
            #include "hash.h"
         | 
| 13 14 | 
             
            #include "oj.h"
         | 
| 14 15 | 
             
            #include "parse.h"
         | 
| 15 16 | 
             
            #include "trace.h"
         | 
| @@ -292,6 +293,27 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) { | |
| 292 293 |  | 
| 293 294 | 
             
            ///// load functions /////
         | 
| 294 295 |  | 
| 296 | 
            +
            static VALUE oj_hash_key(Val parent) {
         | 
| 297 | 
            +
                volatile VALUE rkey = parent->key_val;
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                if (Qundef != rkey) {
         | 
| 300 | 
            +
                    rkey = oj_encode(rkey);
         | 
| 301 | 
            +
                    rkey = rb_str_intern(rkey);
         | 
| 302 | 
            +
             | 
| 303 | 
            +
                    return rkey;
         | 
| 304 | 
            +
                }
         | 
| 305 | 
            +
                VALUE *slot;
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
         | 
| 308 | 
            +
                    rkey  = rb_str_new(parent->key, parent->klen);
         | 
| 309 | 
            +
                    rkey  = oj_encode(rkey);
         | 
| 310 | 
            +
                    rkey  = rb_str_intern(rkey);
         | 
| 311 | 
            +
                    *slot = rkey;
         | 
| 312 | 
            +
                    rb_gc_register_address(slot);
         | 
| 313 | 
            +
                }
         | 
| 314 | 
            +
                return rkey;
         | 
| 315 | 
            +
            }
         | 
| 316 | 
            +
             | 
| 295 317 | 
             
            static void hash_end(ParseInfo pi) {
         | 
| 296 318 | 
             
                if (Yes == pi->options.trace) {
         | 
| 297 319 | 
             
                    oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
         | 
| @@ -432,7 +454,7 @@ static VALUE protect_uri(VALUE rstr) { | |
| 432 454 | 
             
                return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
         | 
| 433 455 | 
             
            }
         | 
| 434 456 |  | 
| 435 | 
            -
            static VALUE cstr_to_rstr(const char *str, size_t len) {
         | 
| 457 | 
            +
            static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
         | 
| 436 458 | 
             
                volatile VALUE v = Qnil;
         | 
| 437 459 |  | 
| 438 460 | 
             
                if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] &&
         | 
| @@ -445,20 +467,20 @@ static VALUE cstr_to_rstr(const char *str, size_t len) { | |
| 445 467 | 
             
                    uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
         | 
| 446 468 | 
             
                    return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
         | 
| 447 469 | 
             
                }
         | 
| 448 | 
            -
                v = rb_str_new(str, len);
         | 
| 449 470 | 
             
                if (7 < len && 0 == strncasecmp("http://", str, 7)) {
         | 
| 450 471 | 
             
                    int            err = 0;
         | 
| 472 | 
            +
            	v = rb_str_new(str, len);
         | 
| 451 473 | 
             
                    volatile VALUE uri = rb_protect(protect_uri, v, &err);
         | 
| 452 474 |  | 
| 453 475 | 
             
                    if (0 == err) {
         | 
| 454 476 | 
             
                        return uri;
         | 
| 455 477 | 
             
                    }
         | 
| 456 478 | 
             
                }
         | 
| 457 | 
            -
                return  | 
| 479 | 
            +
                return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
         | 
| 458 480 | 
             
            }
         | 
| 459 481 |  | 
| 460 482 | 
             
            static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 461 | 
            -
                pi->stack.head->val = cstr_to_rstr(str, len);
         | 
| 483 | 
            +
                pi->stack.head->val = cstr_to_rstr(pi, str, len);
         | 
| 462 484 | 
             
                if (Yes == pi->options.trace) {
         | 
| 463 485 | 
             
                    oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
         | 
| 464 486 | 
             
                }
         | 
| @@ -484,22 +506,10 @@ static VALUE start_hash(ParseInfo pi) { | |
| 484 506 | 
             
                return rb_hash_new();
         | 
| 485 507 | 
             
            }
         | 
| 486 508 |  | 
| 487 | 
            -
            static VALUE calc_hash_key(ParseInfo pi, Val parent) {
         | 
| 488 | 
            -
                volatile VALUE rkey = parent->key_val;
         | 
| 489 | 
            -
             | 
| 490 | 
            -
                if (Qundef == rkey) {
         | 
| 491 | 
            -
                    rkey = rb_str_new(parent->key, parent->klen);
         | 
| 492 | 
            -
                }
         | 
| 493 | 
            -
                rkey = oj_encode(rkey);
         | 
| 494 | 
            -
                rkey = rb_str_intern(rkey);
         | 
| 495 | 
            -
             | 
| 496 | 
            -
                return rkey;
         | 
| 497 | 
            -
            }
         | 
| 498 | 
            -
             | 
| 499 509 | 
             
            static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
         | 
| 500 | 
            -
                volatile VALUE rval = cstr_to_rstr(str, len);
         | 
| 510 | 
            +
                volatile VALUE rval = cstr_to_rstr(pi, str, len);
         | 
| 501 511 |  | 
| 502 | 
            -
                rb_hash_aset(stack_peek(&pi->stack)->val,  | 
| 512 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), rval);
         | 
| 503 513 | 
             
                if (Yes == pi->options.trace) {
         | 
| 504 514 | 
             
                    oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
         | 
| 505 515 | 
             
                }
         | 
| @@ -512,14 +522,14 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { | |
| 512 522 | 
             
                    oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
         | 
| 513 523 | 
             
                }
         | 
| 514 524 | 
             
                rval = oj_num_as_value(ni);
         | 
| 515 | 
            -
                rb_hash_aset(stack_peek(&pi->stack)->val,  | 
| 525 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), rval);
         | 
| 516 526 | 
             
                if (Yes == pi->options.trace) {
         | 
| 517 527 | 
             
                    oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
         | 
| 518 528 | 
             
                }
         | 
| 519 529 | 
             
            }
         | 
| 520 530 |  | 
| 521 531 | 
             
            static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
         | 
| 522 | 
            -
                rb_hash_aset(stack_peek(&pi->stack)->val,  | 
| 532 | 
            +
                rb_hash_aset(stack_peek(&pi->stack)->val, oj_hash_key(parent), value);
         | 
| 523 533 | 
             
                if (Yes == pi->options.trace) {
         | 
| 524 534 | 
             
                    oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
         | 
| 525 535 | 
             
                }
         | 
| @@ -533,7 +543,7 @@ static VALUE start_array(ParseInfo pi) { | |
| 533 543 | 
             
            }
         | 
| 534 544 |  | 
| 535 545 | 
             
            static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
         | 
| 536 | 
            -
                volatile VALUE rval = cstr_to_rstr(str, len);
         | 
| 546 | 
            +
                volatile VALUE rval = cstr_to_rstr(pi, str, len);
         | 
| 537 547 |  | 
| 538 548 | 
             
                rb_ary_push(stack_peek(&pi->stack)->val, rval);
         | 
| 539 549 | 
             
                if (Yes == pi->options.trace) {
         | 
    
        data/lib/oj/version.rb
    CHANGED
    
    
    
        data/test/perf.rb
    CHANGED
    
    
    
        data/test/perf_scp.rb
    CHANGED
    
    | @@ -14,16 +14,16 @@ require 'oj' | |
| 14 14 |  | 
| 15 15 | 
             
            $verbose = false
         | 
| 16 16 | 
             
            $indent = 0
         | 
| 17 | 
            -
            $iter =  | 
| 17 | 
            +
            $iter = 50_000
         | 
| 18 18 | 
             
            $with_bignum = false
         | 
| 19 | 
            -
            $size =  | 
| 19 | 
            +
            $size = 1
         | 
| 20 20 |  | 
| 21 21 | 
             
            opts = OptionParser.new
         | 
| 22 22 | 
             
            opts.on("-v", "verbose")                                  { $verbose = true }
         | 
| 23 23 | 
             
            opts.on("-c", "--count [Int]", Integer, "iterations")     { |i| $iter = i }
         | 
| 24 24 | 
             
            opts.on("-i", "--indent [Int]", Integer, "indentation")   { |i| $indent = i }
         | 
| 25 | 
            -
            opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") | 
| 26 | 
            -
            opts.on("-b", "with bignum") | 
| 25 | 
            +
            opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)")  { |i| $size = i }
         | 
| 26 | 
            +
            opts.on("-b", "with bignum")                              { $with_bignum = true }
         | 
| 27 27 | 
             
            opts.on("-h", "--help", "Show this display")              { puts opts; Process.exit!(0) }
         | 
| 28 28 | 
             
            files = opts.parse(ARGV)
         | 
| 29 29 |  | 
| @@ -47,7 +47,7 @@ if 0 < $size | |
| 47 47 | 
             
              end
         | 
| 48 48 | 
             
            end
         | 
| 49 49 |  | 
| 50 | 
            -
            Oj.default_options = { :indent => $indent, :mode => : | 
| 50 | 
            +
            Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: true, cache_str: 5 }
         | 
| 51 51 |  | 
| 52 52 | 
             
            $json = Oj.dump($obj)
         | 
| 53 53 | 
             
            $failed = {} # key is same as String used in tests later
         | 
| @@ -105,7 +105,7 @@ class AllHandler < Oj::ScHandler | |
| 105 105 |  | 
| 106 106 | 
             
              def hash_set(h, key, value)
         | 
| 107 107 | 
             
              end
         | 
| 108 | 
            -
             | 
| 108 | 
            +
             | 
| 109 109 | 
             
              def array_append(a, value)
         | 
| 110 110 | 
             
              end
         | 
| 111 111 |  | 
| @@ -137,10 +137,11 @@ end | |
| 137 137 | 
             
            puts '-' * 80
         | 
| 138 138 | 
             
            puts "Parse Performance"
         | 
| 139 139 | 
             
            perf = Perf.new()
         | 
| 140 | 
            -
            perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, $json) }
         | 
| 141 | 
            -
            perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, $json) }
         | 
| 142 | 
            -
            perf.add('Oj::Scp', 'all') { Oj.sc_parse(sc_handler, $json) }
         | 
| 143 | 
            -
            perf.add('Oj::Scp', 'none') { Oj.sc_parse(no_handler, $json) }
         | 
| 140 | 
            +
            perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(saj_handler, $json) }
         | 
| 141 | 
            +
            perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_saj, $json) }
         | 
| 142 | 
            +
            perf.add('Oj::Scp.all', 'all') { Oj.sc_parse(sc_handler, $json) }
         | 
| 143 | 
            +
            perf.add('Oj::Scp.none', 'none') { Oj.sc_parse(no_handler, $json) }
         | 
| 144 | 
            +
            perf.add('Oj::load', 'none') { Oj.wab_load($json) }
         | 
| 144 145 | 
             
            perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
         | 
| 145 146 | 
             
            perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
         | 
| 146 147 | 
             
            perf.run($iter)
         | 
    
        data/test/perf_strict.rb
    CHANGED
    
    | @@ -15,6 +15,8 @@ $iter = 20000 | |
| 15 15 | 
             
            $with_bignum = false
         | 
| 16 16 | 
             
            $with_nums = true
         | 
| 17 17 | 
             
            $size = 0
         | 
| 18 | 
            +
            $symbolize = false
         | 
| 19 | 
            +
            $cache_keys = true
         | 
| 18 20 |  | 
| 19 21 | 
             
            opts = OptionParser.new
         | 
| 20 22 | 
             
            opts.on("-v", "verbose")                                    { $verbose = true }
         | 
| @@ -23,6 +25,8 @@ opts.on("-i", "--indent [Int]", Integer, "indentation")     { |i| $indent = i } | |
| 23 25 | 
             
            opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)")    { |i| $size = i }
         | 
| 24 26 | 
             
            opts.on("-b", "with bignum")                                { $with_bignum = true }
         | 
| 25 27 | 
             
            opts.on("-n", "without numbers")                            { $with_nums = false }
         | 
| 28 | 
            +
            opts.on("-z", "--symbolize", "symbolize keys")              { $symbolize = true }
         | 
| 29 | 
            +
            opts.on("-k", "--no-cache", "turn off key caching")         { $cache_keys = false }
         | 
| 26 30 | 
             
            opts.on("-h", "--help", "Show this display")                { puts opts; Process.exit!(0) }
         | 
| 27 31 | 
             
            files = opts.parse(ARGV)
         | 
| 28 32 |  | 
| @@ -51,7 +55,7 @@ else | |
| 51 55 | 
             
              }
         | 
| 52 56 | 
             
            end
         | 
| 53 57 |  | 
| 54 | 
            -
            Oj.default_options = { :indent => $indent, :mode => :strict }
         | 
| 58 | 
            +
            Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: $cache_keys, cache_str: 5 }
         | 
| 55 59 |  | 
| 56 60 | 
             
            if 0 < $size
         | 
| 57 61 | 
             
              o = $obj
         | 
| @@ -62,9 +66,6 @@ if 0 < $size | |
| 62 66 | 
             
            end
         | 
| 63 67 |  | 
| 64 68 | 
             
            $json = Oj.dump($obj)
         | 
| 65 | 
            -
            $obj_json = Oj.dump($obj, :mode => :object)
         | 
| 66 | 
            -
            #puts "*** size: #{$obj_json.size}"
         | 
| 67 | 
            -
            #puts "*** #{$obj_json}"
         | 
| 68 69 | 
             
            $failed = {} # key is same as String used in tests later
         | 
| 69 70 |  | 
| 70 71 | 
             
            def capture_error(tag, orig, load_key, dump_key, &blk)
         | 
| @@ -77,8 +78,13 @@ def capture_error(tag, orig, load_key, dump_key, &blk) | |
| 77 78 | 
             
            end
         | 
| 78 79 |  | 
| 79 80 | 
             
            # Verify that all packages dump and load correctly and return the same Object as the original.
         | 
| 80 | 
            -
            capture_error('Oj:strict', $obj, 'load', 'dump') { |o| | 
| 81 | 
            -
             | 
| 81 | 
            +
            capture_error('Oj:strict', $obj, 'load', 'dump') { |o|
         | 
| 82 | 
            +
              Oj.strict_load(Oj.dump(o))
         | 
| 83 | 
            +
            }
         | 
| 84 | 
            +
            capture_error('Yajl', $obj, 'encode', 'parse') { |o|
         | 
| 85 | 
            +
              require 'yajl'
         | 
| 86 | 
            +
              Yajl::Parser.parse(Yajl::Encoder.encode(o))
         | 
| 87 | 
            +
            }
         | 
| 82 88 | 
             
            capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o|
         | 
| 83 89 | 
             
              require 'json'
         | 
| 84 90 | 
             
              require 'json/ext'
         | 
| @@ -86,16 +92,11 @@ capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| | |
| 86 92 | 
             
              JSON.parser = JSON::Ext::Parser
         | 
| 87 93 | 
             
              JSON.parse(JSON.generate(o))
         | 
| 88 94 | 
             
            }
         | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
              JSON.generator = JSON::Pure::Generator
         | 
| 92 | 
            -
              JSON.parser = JSON::Pure::Parser
         | 
| 93 | 
            -
              JSON.parse(JSON.generate(o))
         | 
| 94 | 
            -
            }
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            Oj.default_options = { symbol_keys: $symbolize }
         | 
| 95 97 |  | 
| 96 98 | 
             
            if $verbose
         | 
| 97 99 | 
             
              puts "json:\n#{$json}\n"
         | 
| 98 | 
            -
              puts "object json:\n#{$obj_json}\n"
         | 
| 99 100 | 
             
              puts "Oj loaded object:\n#{Oj.strict_load($json)}\n"
         | 
| 100 101 | 
             
              puts "Yajl loaded object:\n#{Yajl::Parser.parse($json)}\n"
         | 
| 101 102 | 
             
              puts "JSON loaded object:\n#{JSON::Ext::Parser.new($json).parse}\n"
         | 
| @@ -105,15 +106,12 @@ puts '-' * 80 | |
| 105 106 | 
             
            puts "Strict Parse Performance"
         | 
| 106 107 | 
             
            perf = Perf.new()
         | 
| 107 108 | 
             
            unless $failed.has_key?('JSON::Ext')
         | 
| 108 | 
            -
              perf.add('JSON::Ext', 'parse') { JSON.parse($json) }
         | 
| 109 | 
            +
              perf.add('JSON::Ext', 'parse') { JSON.parse($json, symbolize_names: $symbolize) }
         | 
| 109 110 | 
             
              perf.before('JSON::Ext') { JSON.parser = JSON::Ext::Parser }
         | 
| 110 111 | 
             
            end
         | 
| 111 | 
            -
            unless $failed.has_key?('JSON::Pure')
         | 
| 112 | 
            -
              perf.add('JSON::Pure', 'parse') { JSON.parse($json) }
         | 
| 113 | 
            -
              perf.before('JSON::Pure') { JSON.parser = JSON::Pure::Parser }
         | 
| 114 | 
            -
            end
         | 
| 115 112 | 
             
            unless $failed.has_key?('Oj:strict')
         | 
| 116 113 | 
             
              perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json) }
         | 
| 114 | 
            +
              perf.add('Oj:wab', 'wab_load') { Oj.wab_load($json) }
         | 
| 117 115 | 
             
            end
         | 
| 118 116 | 
             
            perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
         | 
| 119 117 | 
             
            perf.run($iter)
         | 
| @@ -125,12 +123,8 @@ unless $failed.has_key?('JSON::Ext') | |
| 125 123 | 
             
              perf.add('JSON::Ext', 'dump') { JSON.generate($obj) }
         | 
| 126 124 | 
             
              perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
         | 
| 127 125 | 
             
            end
         | 
| 128 | 
            -
            unless $failed.has_key?('JSON::Pure')
         | 
| 129 | 
            -
              perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
         | 
| 130 | 
            -
              perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator }
         | 
| 131 | 
            -
            end
         | 
| 132 126 | 
             
            unless $failed.has_key?('Oj:strict')
         | 
| 133 | 
            -
              perf.add('Oj:strict', 'dump') { Oj.dump($obj | 
| 127 | 
            +
              perf.add('Oj:strict', 'dump') { Oj.dump($obj) }
         | 
| 134 128 | 
             
            end
         | 
| 135 129 | 
             
            perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) } unless $failed.has_key?('Yajl')
         | 
| 136 130 | 
             
            perf.run($iter)
         | 
    
        data/test/test_various.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: oj
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3. | 
| 4 | 
            +
              version: 3.12.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Peter Ohler
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-07- | 
| 11 | 
            +
            date: 2021-07-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake-compiler
         |