oj 3.12.2 → 3.13.2
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/README.md +2 -3
- data/ext/oj/buf.h +9 -0
- data/ext/oj/cache.c +193 -0
- data/ext/oj/cache.h +20 -0
- data/ext/oj/compat.c +8 -22
- data/ext/oj/custom.c +15 -14
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +12 -15
- data/ext/oj/dump_compat.c +3 -3
- data/ext/oj/dump_object.c +9 -9
- data/ext/oj/dump_strict.c +3 -3
- data/ext/oj/err.h +19 -0
- data/ext/oj/extconf.rb +4 -0
- data/ext/oj/fast.c +7 -18
- data/ext/oj/intern.c +398 -0
- data/ext/oj/intern.h +27 -0
- data/ext/oj/mimic_json.c +9 -9
- data/ext/oj/object.c +11 -59
- data/ext/oj/odd.c +1 -1
- data/ext/oj/oj.c +167 -109
- data/ext/oj/oj.h +2 -2
- data/ext/oj/parse.c +5 -5
- data/ext/oj/parser.c +1512 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +5 -5
- data/ext/oj/resolve.c +2 -20
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/saj.c +1 -1
- data/ext/oj/saj2.c +348 -0
- data/ext/oj/scp.c +1 -1
- data/ext/oj/sparse.c +2 -2
- data/ext/oj/stream_writer.c +4 -4
- data/ext/oj/strict.c +10 -27
- data/ext/oj/string_writer.c +2 -2
- data/ext/oj/usual.c +1228 -0
- data/ext/oj/validate.c +51 -0
- data/ext/oj/wab.c +9 -17
- data/lib/oj/error.rb +1 -1
- data/lib/oj/mimic.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Modes.md +2 -0
- data/pages/Options.md +17 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +2 -2
- data/test/json_gem/json_generator_test.rb +1 -1
- data/test/perf_parser.rb +184 -0
- data/test/test_hash.rb +1 -1
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -0
- data/test/test_parser_usual.rb +213 -0
- metadata +22 -5
- data/ext/oj/hash.c +0 -168
- data/ext/oj/hash.h +0 -21
- data/ext/oj/hash_test.c +0 -491
| @@ -0,0 +1,213 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            $: << File.dirname(__FILE__)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'helper'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class UsualTest < Minitest::Test
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def test_nil
         | 
| 11 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 12 | 
            +
                doc = p.parse('nil')
         | 
| 13 | 
            +
                assert_nil(doc)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def test_primitive
         | 
| 17 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 18 | 
            +
                [
         | 
| 19 | 
            +
                  ['true', true],
         | 
| 20 | 
            +
                  ['false', false],
         | 
| 21 | 
            +
                  ['123', 123],
         | 
| 22 | 
            +
                  ['1.25', 1.25],
         | 
| 23 | 
            +
                  ['"abc"', 'abc'],
         | 
| 24 | 
            +
                ].each { |x|
         | 
| 25 | 
            +
                  doc = p.parse(x[0])
         | 
| 26 | 
            +
                  assert_equal(x[1], doc)
         | 
| 27 | 
            +
                }
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def test_big
         | 
| 31 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 32 | 
            +
                doc = p.parse('12345678901234567890123456789')
         | 
| 33 | 
            +
                assert_equal(BigDecimal, doc.class)
         | 
| 34 | 
            +
                doc = p.parse('1234567890.1234567890123456789')
         | 
| 35 | 
            +
                assert_equal(BigDecimal, doc.class)
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def test_array
         | 
| 39 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 40 | 
            +
                [
         | 
| 41 | 
            +
                  ['[]', []],
         | 
| 42 | 
            +
                  ['[false]', [false]],
         | 
| 43 | 
            +
                  ['[true,false]', [true,false]],
         | 
| 44 | 
            +
                  ['[[]]', [[]]],
         | 
| 45 | 
            +
                  ['[true,[],false]', [true,[],false]],
         | 
| 46 | 
            +
                  ['[true,[true],false]', [true,[true],false]],
         | 
| 47 | 
            +
                ].each { |x|
         | 
| 48 | 
            +
                  doc = p.parse(x[0])
         | 
| 49 | 
            +
                  assert_equal(x[1], doc)
         | 
| 50 | 
            +
                }
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def test_hash
         | 
| 54 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 55 | 
            +
                [
         | 
| 56 | 
            +
                  ['{}', {}],
         | 
| 57 | 
            +
                  ['{"a": null}', {'a' => nil}],
         | 
| 58 | 
            +
                  ['{"t": true, "f": false, "s": "abc"}', {'t' => true, 'f' => false, 's' => 'abc'}],
         | 
| 59 | 
            +
                  ['{"a": {}}', {'a' => {}}],
         | 
| 60 | 
            +
                  ['{"a": {"b": 2}}', {'a' => {'b' => 2}}],
         | 
| 61 | 
            +
                  ['{"a": [true]}', {'a' => [true]}],
         | 
| 62 | 
            +
                ].each { |x|
         | 
| 63 | 
            +
                  doc = p.parse(x[0])
         | 
| 64 | 
            +
                  assert_equal(x[1], doc)
         | 
| 65 | 
            +
                }
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              def test_symbol_keys
         | 
| 69 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 70 | 
            +
                assert_equal(false, p.symbol_keys)
         | 
| 71 | 
            +
                p.symbol_keys = true
         | 
| 72 | 
            +
                doc = p.parse('{"a": true, "b": false}')
         | 
| 73 | 
            +
                assert_equal({a: true, b: false}, doc)
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              def test_capacity
         | 
| 77 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 78 | 
            +
                p.capacity = 1000
         | 
| 79 | 
            +
                assert_equal(4096, p.capacity)
         | 
| 80 | 
            +
                p.capacity = 5000
         | 
| 81 | 
            +
                assert_equal(5000, p.capacity)
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              def test_decimal
         | 
| 85 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 86 | 
            +
                assert_equal(:auto, p.decimal)
         | 
| 87 | 
            +
                doc = p.parse('1.234567890123456789')
         | 
| 88 | 
            +
                assert_equal(BigDecimal, doc.class)
         | 
| 89 | 
            +
                assert_equal('0.1234567890123456789e1', doc.to_s)
         | 
| 90 | 
            +
                doc = p.parse('1.25')
         | 
| 91 | 
            +
                assert_equal(Float, doc.class)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                p.decimal = :float
         | 
| 94 | 
            +
                assert_equal(:float, p.decimal)
         | 
| 95 | 
            +
                doc = p.parse('1.234567890123456789')
         | 
| 96 | 
            +
                assert_equal(Float, doc.class)
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                p.decimal = :bigdecimal
         | 
| 99 | 
            +
                assert_equal(:bigdecimal, p.decimal)
         | 
| 100 | 
            +
                doc = p.parse('1.234567890123456789')
         | 
| 101 | 
            +
                assert_equal(BigDecimal, doc.class)
         | 
| 102 | 
            +
                doc = p.parse('1.25')
         | 
| 103 | 
            +
                assert_equal(BigDecimal, doc.class)
         | 
| 104 | 
            +
                assert_equal('0.125e1', doc.to_s)
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                p.decimal = :ruby
         | 
| 107 | 
            +
                assert_equal(:ruby, p.decimal)
         | 
| 108 | 
            +
                doc = p.parse('1.234567890123456789')
         | 
| 109 | 
            +
                assert_equal(Float, doc.class)
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              def test_omit_null
         | 
| 113 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 114 | 
            +
                p.omit_null = true
         | 
| 115 | 
            +
                doc = p.parse('{"a":true,"b":null}')
         | 
| 116 | 
            +
                assert_equal({'a'=>true}, doc)
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                p.omit_null = false
         | 
| 119 | 
            +
                doc = p.parse('{"a":true,"b":null}')
         | 
| 120 | 
            +
                assert_equal({'a'=>true, 'b'=>nil}, doc)
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
              class MyArray < Array
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              def test_array_class
         | 
| 127 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 128 | 
            +
                p.array_class = MyArray
         | 
| 129 | 
            +
                assert_equal(MyArray, p.array_class)
         | 
| 130 | 
            +
                doc = p.parse('[true]')
         | 
| 131 | 
            +
                assert_equal(MyArray, doc.class)
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              class MyHash < Hash
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              def test_hash_class
         | 
| 138 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 139 | 
            +
                p.hash_class = MyHash
         | 
| 140 | 
            +
                assert_equal(MyHash, p.hash_class)
         | 
| 141 | 
            +
                doc = p.parse('{"a":true}')
         | 
| 142 | 
            +
                assert_equal(MyHash, doc.class)
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              class MyClass
         | 
| 146 | 
            +
                attr_accessor :a
         | 
| 147 | 
            +
                attr_accessor :b
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                def to_s
         | 
| 150 | 
            +
                  "#{self.class}{a: #{@a} b: #{b}}"
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
              end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
              class MyClass2 < MyClass
         | 
| 155 | 
            +
                def self.json_create(arg)
         | 
| 156 | 
            +
                  obj = new
         | 
| 157 | 
            +
                  obj.a = arg['a']
         | 
| 158 | 
            +
                  obj.b = arg['b']
         | 
| 159 | 
            +
                  obj
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
              end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
              def test_create_id
         | 
| 164 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 165 | 
            +
                p.create_id = '^'
         | 
| 166 | 
            +
                doc = p.parse('{"a":true}')
         | 
| 167 | 
            +
                assert_equal(Hash, doc.class)
         | 
| 168 | 
            +
                doc = p.parse('{"a":true,"^":"UsualTest::MyClass","b":false}')
         | 
| 169 | 
            +
                assert_equal('UsualTest::MyClass{a: true b: false}', doc.to_s)
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                doc = p.parse('{"a":true,"^":"UsualTest::MyClass2","b":false}')
         | 
| 172 | 
            +
                assert_equal('UsualTest::MyClass2{a: true b: false}', doc.to_s)
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                p.hash_class = MyHash
         | 
| 175 | 
            +
                assert_equal(MyHash, p.hash_class)
         | 
| 176 | 
            +
                doc = p.parse('{"a":true}')
         | 
| 177 | 
            +
                assert_equal(MyHash, doc.class)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                doc = p.parse('{"a":true,"^":"UsualTest::MyClass","b":false}')
         | 
| 180 | 
            +
                assert_equal('UsualTest::MyClass{a: true b: false}', doc.to_s)
         | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
              def test_missing_class
         | 
| 184 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 185 | 
            +
                p.create_id = '^'
         | 
| 186 | 
            +
                json = '{"a":true,"^":"Auto","b":false}'
         | 
| 187 | 
            +
                doc = p.parse(json)
         | 
| 188 | 
            +
                assert_equal(Hash, doc.class)
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                p.missing_class = :auto
         | 
| 191 | 
            +
                doc = p.parse(json)
         | 
| 192 | 
            +
                # Auto should be defined after parsing
         | 
| 193 | 
            +
                assert_equal(Auto, doc.class)
         | 
| 194 | 
            +
              end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
              def test_class_cache
         | 
| 197 | 
            +
                p = Oj::Parser.new(:usual)
         | 
| 198 | 
            +
                p.create_id = '^'
         | 
| 199 | 
            +
                p.class_cache = true
         | 
| 200 | 
            +
                p.missing_class = :auto
         | 
| 201 | 
            +
                json = '{"a":true,"^":"Auto2","b":false}'
         | 
| 202 | 
            +
                doc = p.parse(json)
         | 
| 203 | 
            +
                assert_equal(Auto2, doc.class)
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                doc = p.parse(json)
         | 
| 206 | 
            +
                assert_equal(Auto2, doc.class)
         | 
| 207 | 
            +
              end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
              def test_default_parser
         | 
| 210 | 
            +
                doc = Oj::Parser.usual.parse('{"a":true,"b":null}')
         | 
| 211 | 
            +
                assert_equal({'a'=>true, 'b'=>nil}, doc)
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
            end
         | 
    
        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.13.2
         | 
| 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- | 
| 11 | 
            +
            date: 2021-08-16 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake-compiler
         | 
| @@ -86,6 +86,7 @@ extra_rdoc_files: | |
| 86 86 | 
             
            - pages/JsonGem.md
         | 
| 87 87 | 
             
            - pages/Modes.md
         | 
| 88 88 | 
             
            - pages/Options.md
         | 
| 89 | 
            +
            - pages/Parser.md
         | 
| 89 90 | 
             
            - pages/Rails.md
         | 
| 90 91 | 
             
            - pages/Security.md
         | 
| 91 92 | 
             
            - pages/WAB.md
         | 
| @@ -93,6 +94,8 @@ files: | |
| 93 94 | 
             
            - LICENSE
         | 
| 94 95 | 
             
            - README.md
         | 
| 95 96 | 
             
            - ext/oj/buf.h
         | 
| 97 | 
            +
            - ext/oj/cache.c
         | 
| 98 | 
            +
            - ext/oj/cache.h
         | 
| 96 99 | 
             
            - ext/oj/cache8.c
         | 
| 97 100 | 
             
            - ext/oj/cache8.h
         | 
| 98 101 | 
             
            - ext/oj/circarray.c
         | 
| @@ -101,6 +104,7 @@ files: | |
| 101 104 | 
             
            - ext/oj/code.h
         | 
| 102 105 | 
             
            - ext/oj/compat.c
         | 
| 103 106 | 
             
            - ext/oj/custom.c
         | 
| 107 | 
            +
            - ext/oj/debug.c
         | 
| 104 108 | 
             
            - ext/oj/dump.c
         | 
| 105 109 | 
             
            - ext/oj/dump.h
         | 
| 106 110 | 
             
            - ext/oj/dump_compat.c
         | 
| @@ -112,9 +116,8 @@ files: | |
| 112 116 | 
             
            - ext/oj/err.h
         | 
| 113 117 | 
             
            - ext/oj/extconf.rb
         | 
| 114 118 | 
             
            - ext/oj/fast.c
         | 
| 115 | 
            -
            - ext/oj/ | 
| 116 | 
            -
            - ext/oj/ | 
| 117 | 
            -
            - ext/oj/hash_test.c
         | 
| 119 | 
            +
            - ext/oj/intern.c
         | 
| 120 | 
            +
            - ext/oj/intern.h
         | 
| 118 121 | 
             
            - ext/oj/mimic_json.c
         | 
| 119 122 | 
             
            - ext/oj/object.c
         | 
| 120 123 | 
             
            - ext/oj/odd.c
         | 
| @@ -123,6 +126,8 @@ files: | |
| 123 126 | 
             
            - ext/oj/oj.h
         | 
| 124 127 | 
             
            - ext/oj/parse.c
         | 
| 125 128 | 
             
            - ext/oj/parse.h
         | 
| 129 | 
            +
            - ext/oj/parser.c
         | 
| 130 | 
            +
            - ext/oj/parser.h
         | 
| 126 131 | 
             
            - ext/oj/rails.c
         | 
| 127 132 | 
             
            - ext/oj/rails.h
         | 
| 128 133 | 
             
            - ext/oj/reader.c
         | 
| @@ -132,6 +137,7 @@ files: | |
| 132 137 | 
             
            - ext/oj/rxclass.c
         | 
| 133 138 | 
             
            - ext/oj/rxclass.h
         | 
| 134 139 | 
             
            - ext/oj/saj.c
         | 
| 140 | 
            +
            - ext/oj/saj2.c
         | 
| 135 141 | 
             
            - ext/oj/scp.c
         | 
| 136 142 | 
             
            - ext/oj/sparse.c
         | 
| 137 143 | 
             
            - ext/oj/stream_writer.c
         | 
| @@ -139,10 +145,12 @@ files: | |
| 139 145 | 
             
            - ext/oj/string_writer.c
         | 
| 140 146 | 
             
            - ext/oj/trace.c
         | 
| 141 147 | 
             
            - ext/oj/trace.h
         | 
| 148 | 
            +
            - ext/oj/usual.c
         | 
| 142 149 | 
             
            - ext/oj/util.c
         | 
| 143 150 | 
             
            - ext/oj/util.h
         | 
| 144 151 | 
             
            - ext/oj/val_stack.c
         | 
| 145 152 | 
             
            - ext/oj/val_stack.h
         | 
| 153 | 
            +
            - ext/oj/validate.c
         | 
| 146 154 | 
             
            - ext/oj/wab.c
         | 
| 147 155 | 
             
            - lib/oj.rb
         | 
| 148 156 | 
             
            - lib/oj/active_support_helper.rb
         | 
| @@ -162,6 +170,7 @@ files: | |
| 162 170 | 
             
            - pages/JsonGem.md
         | 
| 163 171 | 
             
            - pages/Modes.md
         | 
| 164 172 | 
             
            - pages/Options.md
         | 
| 173 | 
            +
            - pages/Parser.md
         | 
| 165 174 | 
             
            - pages/Rails.md
         | 
| 166 175 | 
             
            - pages/Security.md
         | 
| 167 176 | 
             
            - pages/WAB.md
         | 
| @@ -214,6 +223,7 @@ files: | |
| 214 223 | 
             
            - test/perf_fast.rb
         | 
| 215 224 | 
             
            - test/perf_file.rb
         | 
| 216 225 | 
             
            - test/perf_object.rb
         | 
| 226 | 
            +
            - test/perf_parser.rb
         | 
| 217 227 | 
             
            - test/perf_saj.rb
         | 
| 218 228 | 
             
            - test/perf_scp.rb
         | 
| 219 229 | 
             
            - test/perf_simple.rb
         | 
| @@ -245,6 +255,9 @@ files: | |
| 245 255 | 
             
            - test/test_integer_range.rb
         | 
| 246 256 | 
             
            - test/test_null.rb
         | 
| 247 257 | 
             
            - test/test_object.rb
         | 
| 258 | 
            +
            - test/test_parser.rb
         | 
| 259 | 
            +
            - test/test_parser_saj.rb
         | 
| 260 | 
            +
            - test/test_parser_usual.rb
         | 
| 248 261 | 
             
            - test/test_rails.rb
         | 
| 249 262 | 
             
            - test/test_saj.rb
         | 
| 250 263 | 
             
            - test/test_scp.rb
         | 
| @@ -339,6 +352,7 @@ test_files: | |
| 339 352 | 
             
            - test/perf_fast.rb
         | 
| 340 353 | 
             
            - test/perf_file.rb
         | 
| 341 354 | 
             
            - test/perf_object.rb
         | 
| 355 | 
            +
            - test/perf_parser.rb
         | 
| 342 356 | 
             
            - test/perf_saj.rb
         | 
| 343 357 | 
             
            - test/perf_scp.rb
         | 
| 344 358 | 
             
            - test/perf_simple.rb
         | 
| @@ -370,6 +384,9 @@ test_files: | |
| 370 384 | 
             
            - test/test_integer_range.rb
         | 
| 371 385 | 
             
            - test/test_null.rb
         | 
| 372 386 | 
             
            - test/test_object.rb
         | 
| 387 | 
            +
            - test/test_parser.rb
         | 
| 388 | 
            +
            - test/test_parser_saj.rb
         | 
| 389 | 
            +
            - test/test_parser_usual.rb
         | 
| 373 390 | 
             
            - test/test_rails.rb
         | 
| 374 391 | 
             
            - test/test_saj.rb
         | 
| 375 392 | 
             
            - test/test_scp.rb
         | 
    
        data/ext/oj/hash.c
    DELETED
    
    | @@ -1,168 +0,0 @@ | |
| 1 | 
            -
            // Copyright (c) 2011 Peter Ohler. All rights reserved.
         | 
| 2 | 
            -
            // Licensed under the MIT License. See LICENSE file in the project root for license details.
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            #include "hash.h"
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            #include <stdint.h>
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            #define HASH_SLOT_CNT ((uint32_t)8192)
         | 
| 9 | 
            -
            #define HASH_MASK (HASH_SLOT_CNT - 1)
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            typedef struct _keyVal {
         | 
| 12 | 
            -
                struct _keyVal *next;
         | 
| 13 | 
            -
                const char *    key;
         | 
| 14 | 
            -
                size_t          len;
         | 
| 15 | 
            -
                VALUE           val;
         | 
| 16 | 
            -
            } * KeyVal;
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            struct _hash {
         | 
| 19 | 
            -
                struct _keyVal slots[HASH_SLOT_CNT];
         | 
| 20 | 
            -
            };
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            struct _hash class_hash;
         | 
| 23 | 
            -
            struct _hash str_hash;
         | 
| 24 | 
            -
            struct _hash sym_hash;
         | 
| 25 | 
            -
            struct _hash intern_hash;
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            // almost the Murmur hash algorithm
         | 
| 28 | 
            -
            #define M 0x5bd1e995
         | 
| 29 | 
            -
            #define C1 0xCC9E2D51
         | 
| 30 | 
            -
            #define C2 0x1B873593
         | 
| 31 | 
            -
            #define N 0xE6546B64
         | 
| 32 | 
            -
             | 
| 33 | 
            -
            static uint32_t hash_calc(const uint8_t *key, size_t len) {
         | 
| 34 | 
            -
                const uint8_t *end     = key + len;
         | 
| 35 | 
            -
                const uint8_t *endless = key + (len / 4 * 4);
         | 
| 36 | 
            -
                uint32_t       h       = (uint32_t)len;
         | 
| 37 | 
            -
                uint32_t       k;
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                while (key < endless) {
         | 
| 40 | 
            -
                    k = (uint32_t)*key++;
         | 
| 41 | 
            -
                    k |= (uint32_t)*key++ << 8;
         | 
| 42 | 
            -
                    k |= (uint32_t)*key++ << 16;
         | 
| 43 | 
            -
                    k |= (uint32_t)*key++ << 24;
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                    k *= M;
         | 
| 46 | 
            -
                    k ^= k >> 24;
         | 
| 47 | 
            -
                    h *= M;
         | 
| 48 | 
            -
                    h ^= k * M;
         | 
| 49 | 
            -
                }
         | 
| 50 | 
            -
                if (1 < end - key) {
         | 
| 51 | 
            -
                    uint16_t k16 = (uint16_t)*key++;
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                    k16 |= (uint16_t)*key++ << 8;
         | 
| 54 | 
            -
                    h ^= k16 << 8;
         | 
| 55 | 
            -
                }
         | 
| 56 | 
            -
                if (key < end) {
         | 
| 57 | 
            -
                    h ^= *key;
         | 
| 58 | 
            -
                }
         | 
| 59 | 
            -
                h *= M;
         | 
| 60 | 
            -
                h ^= h >> 13;
         | 
| 61 | 
            -
                h *= M;
         | 
| 62 | 
            -
                h ^= h >> 15;
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                return h;
         | 
| 65 | 
            -
            }
         | 
| 66 | 
            -
             | 
| 67 | 
            -
            void oj_hash_init() {
         | 
| 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));
         | 
| 71 | 
            -
                memset(intern_hash.slots, 0, sizeof(intern_hash.slots));
         | 
| 72 | 
            -
            }
         | 
| 73 | 
            -
             | 
| 74 | 
            -
            // if slotp is 0 then just lookup
         | 
| 75 | 
            -
            static VALUE hash_get(Hash hash, const char *key, size_t len, VALUE **slotp, VALUE def_value) {
         | 
| 76 | 
            -
                uint32_t h      = hash_calc((const uint8_t *)key, len) & HASH_MASK;
         | 
| 77 | 
            -
                KeyVal   bucket = hash->slots + h;
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                if (0 != bucket->key) {
         | 
| 80 | 
            -
                    KeyVal b;
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                    for (b = bucket; 0 != b; b = b->next) {
         | 
| 83 | 
            -
                        if (len == b->len && 0 == strncmp(b->key, key, len)) {
         | 
| 84 | 
            -
                            *slotp = &b->val;
         | 
| 85 | 
            -
                            return b->val;
         | 
| 86 | 
            -
                        }
         | 
| 87 | 
            -
                        bucket = b;
         | 
| 88 | 
            -
                    }
         | 
| 89 | 
            -
                }
         | 
| 90 | 
            -
                if (0 != slotp) {
         | 
| 91 | 
            -
                    if (0 != bucket->key) {
         | 
| 92 | 
            -
                        KeyVal b = ALLOC(struct _keyVal);
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                        b->next      = 0;
         | 
| 95 | 
            -
                        bucket->next = b;
         | 
| 96 | 
            -
                        bucket       = b;
         | 
| 97 | 
            -
                    }
         | 
| 98 | 
            -
                    bucket->key = oj_strndup(key, len);
         | 
| 99 | 
            -
                    bucket->len = len;
         | 
| 100 | 
            -
                    bucket->val = def_value;
         | 
| 101 | 
            -
                    *slotp      = &bucket->val;
         | 
| 102 | 
            -
                }
         | 
| 103 | 
            -
                return def_value;
         | 
| 104 | 
            -
            }
         | 
| 105 | 
            -
             | 
| 106 | 
            -
            void oj_hash_print() {
         | 
| 107 | 
            -
                uint32_t i;
         | 
| 108 | 
            -
                KeyVal   b;
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                for (i = 0; i < HASH_SLOT_CNT; i++) {
         | 
| 111 | 
            -
                    printf("%4d:", i);
         | 
| 112 | 
            -
                    for (b = class_hash.slots + i; 0 != b && 0 != b->key; b = b->next) {
         | 
| 113 | 
            -
                        printf(" %s", b->key);
         | 
| 114 | 
            -
                    }
         | 
| 115 | 
            -
                    printf("\n");
         | 
| 116 | 
            -
                }
         | 
| 117 | 
            -
            }
         | 
| 118 | 
            -
             | 
| 119 | 
            -
            void oj_hash_sizes() {
         | 
| 120 | 
            -
                uint32_t i;
         | 
| 121 | 
            -
                KeyVal   b;
         | 
| 122 | 
            -
                int      max = 0;
         | 
| 123 | 
            -
                int      min = 1000000;
         | 
| 124 | 
            -
             | 
| 125 | 
            -
                for (i = 0; i < HASH_SLOT_CNT; i++) {
         | 
| 126 | 
            -
                    int cnt = 0;
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                    for (b = str_hash.slots + i; 0 != b && 0 != b->key; b = b->next) {
         | 
| 129 | 
            -
                        cnt++;
         | 
| 130 | 
            -
                    }
         | 
| 131 | 
            -
                    // printf(" %4d\n", cnt);
         | 
| 132 | 
            -
                    if (max < cnt) {
         | 
| 133 | 
            -
                        max = cnt;
         | 
| 134 | 
            -
                    }
         | 
| 135 | 
            -
                    if (cnt < min) {
         | 
| 136 | 
            -
                        min = cnt;
         | 
| 137 | 
            -
                    }
         | 
| 138 | 
            -
                }
         | 
| 139 | 
            -
                printf("min: %d  max: %d\n", min, max);
         | 
| 140 | 
            -
            }
         | 
| 141 | 
            -
             | 
| 142 | 
            -
            VALUE
         | 
| 143 | 
            -
            oj_class_hash_get(const char *key, size_t len, VALUE **slotp) {
         | 
| 144 | 
            -
                return hash_get(&class_hash, key, len, slotp, Qnil);
         | 
| 145 | 
            -
            }
         | 
| 146 | 
            -
             | 
| 147 | 
            -
            VALUE
         | 
| 148 | 
            -
            oj_str_hash_get(const char *key, size_t len, VALUE **slotp) {
         | 
| 149 | 
            -
                return hash_get(&str_hash, key, len, slotp, Qnil);
         | 
| 150 | 
            -
            }
         | 
| 151 | 
            -
             | 
| 152 | 
            -
            VALUE
         | 
| 153 | 
            -
            oj_sym_hash_get(const char *key, size_t len, VALUE **slotp) {
         | 
| 154 | 
            -
                return hash_get(&sym_hash, key, len, slotp, Qnil);
         | 
| 155 | 
            -
            }
         | 
| 156 | 
            -
             | 
| 157 | 
            -
            ID oj_attr_hash_get(const char *key, size_t len, ID **slotp) {
         | 
| 158 | 
            -
                return (ID)hash_get(&intern_hash, key, len, (VALUE **)slotp, 0);
         | 
| 159 | 
            -
            }
         | 
| 160 | 
            -
             | 
| 161 | 
            -
            char *oj_strndup(const char *s, size_t len) {
         | 
| 162 | 
            -
                char *d = ALLOC_N(char, len + 1);
         | 
| 163 | 
            -
             | 
| 164 | 
            -
                memcpy(d, s, len);
         | 
| 165 | 
            -
                d[len] = '\0';
         | 
| 166 | 
            -
             | 
| 167 | 
            -
                return d;
         | 
| 168 | 
            -
            }
         |