oj 3.11.5 → 3.16.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1421 -0
- data/README.md +19 -5
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +20 -6
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +8 -6
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +19 -33
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +27 -77
- data/ext/oj/custom.c +86 -179
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +256 -249
- data/ext/oj/dump.h +26 -12
- data/ext/oj/dump_compat.c +565 -642
- data/ext/oj/dump_leaf.c +17 -63
- data/ext/oj/dump_object.c +65 -187
- data/ext/oj/dump_strict.c +27 -51
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +2 -13
- data/ext/oj/err.h +24 -8
- data/ext/oj/extconf.rb +21 -6
- data/ext/oj/fast.c +149 -149
- data/ext/oj/intern.c +313 -0
- data/ext/oj/intern.h +22 -0
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +121 -106
- data/ext/oj/object.c +85 -162
- data/ext/oj/odd.c +89 -67
- data/ext/oj/odd.h +15 -15
- data/ext/oj/oj.c +542 -411
- data/ext/oj/oj.h +99 -73
- data/ext/oj/parse.c +175 -187
- data/ext/oj/parse.h +26 -24
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +101 -0
- data/ext/oj/rails.c +112 -159
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +11 -14
- data/ext/oj/reader.h +4 -2
- data/ext/oj/resolve.c +5 -24
- data/ext/oj/rxclass.c +7 -6
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/saj.c +22 -33
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +5 -28
- data/ext/oj/sparse.c +28 -72
- data/ext/oj/stream_writer.c +50 -40
- data/ext/oj/strict.c +56 -61
- data/ext/oj/string_writer.c +72 -39
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +14 -3
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +63 -88
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +7 -1
- data/lib/oj/easy_hash.rb +4 -5
- data/lib/oj/error.rb +1 -2
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +9 -7
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +12 -8
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +8 -3
- data/pages/Options.md +43 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +14 -2
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +5 -6
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +16 -45
- data/test/helper.rb +11 -8
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +56 -38
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +7 -3
- data/test/mem.rb +34 -0
- data/test/perf.rb +22 -27
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +59 -0
- data/test/perf_parser.rb +183 -0
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +58 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +74 -82
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +95 -43
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +135 -79
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +5 -5
- data/test/test_hash.rb +5 -5
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +99 -96
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +337 -0
- data/test/test_parser_usual.rb +251 -0
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +37 -39
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +165 -84
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -5
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +74 -128
- data/ext/oj/hash.c +0 -131
- data/ext/oj/hash.h +0 -19
- data/ext/oj/hash_test.c +0 -491
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/bar.rb +0 -35
- data/test/baz.rb +0 -16
- data/test/zoo.rb +0 -13
data/test/perf_object.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
$LOAD_PATH << '.'
|
5
|
+
$LOAD_PATH << '../lib'
|
6
|
+
$LOAD_PATH << '../ext'
|
6
7
|
|
7
|
-
if __FILE__ == $
|
8
|
-
|
9
|
-
|
10
|
-
$: << path
|
11
|
-
end
|
8
|
+
if __FILE__ == $PROGRAM_NAME && (i = ARGV.index('-I'))
|
9
|
+
_, path = ARGV.slice!(i, 2)
|
10
|
+
$LOAD_PATH << path
|
12
11
|
end
|
13
12
|
|
14
13
|
require 'optparse'
|
@@ -18,9 +17,9 @@ require 'perf'
|
|
18
17
|
require 'sample'
|
19
18
|
require 'files'
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
@circular = false
|
21
|
+
@indent = 0
|
22
|
+
@allow_gc = true
|
24
23
|
|
25
24
|
do_sample = false
|
26
25
|
do_files = false
|
@@ -29,34 +28,34 @@ do_load = false
|
|
29
28
|
do_dump = false
|
30
29
|
do_read = false
|
31
30
|
do_write = false
|
32
|
-
|
33
|
-
|
31
|
+
@iter = 1000
|
32
|
+
@mult = 1
|
34
33
|
|
35
34
|
opts = OptionParser.new
|
36
|
-
opts.on(
|
35
|
+
opts.on('-c', 'circular options') { @circular = true }
|
37
36
|
|
38
|
-
opts.on(
|
39
|
-
opts.on(
|
37
|
+
opts.on('-x', 'use sample instead of files') { do_sample = true }
|
38
|
+
opts.on('-g', 'no GC during parsing') { @allow_gc = false }
|
40
39
|
|
41
|
-
opts.on(
|
42
|
-
opts.on(
|
40
|
+
opts.on('-s', 'load and dump as sample Ruby object') { do_sample = true }
|
41
|
+
opts.on('-f', 'load and dump as files Ruby object') { do_files = true }
|
43
42
|
|
44
|
-
opts.on(
|
45
|
-
opts.on(
|
46
|
-
opts.on(
|
47
|
-
opts.on(
|
48
|
-
opts.on(
|
43
|
+
opts.on('-l', 'load') { do_load = true }
|
44
|
+
opts.on('-d', 'dump') { do_dump = true }
|
45
|
+
opts.on('-r', 'read') { do_read = true }
|
46
|
+
opts.on('-w', 'write') { do_write = true }
|
47
|
+
opts.on('-a', 'load, dump, read and write') { do_load = true; do_dump = true; do_read = true; do_write = true }
|
49
48
|
|
50
|
-
opts.on(
|
51
|
-
opts.on(
|
49
|
+
opts.on('-i', '--iterations [Int]', Integer, 'iterations') { |v| @iter = v }
|
50
|
+
opts.on('-m', '--multiply [Int]', Integer, 'multiplier') { |v| @mult = v }
|
52
51
|
|
53
|
-
opts.on(
|
52
|
+
opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
|
54
53
|
files = opts.parse(ARGV)
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
@obj = nil
|
56
|
+
@xml = nil
|
57
|
+
@mars = nil
|
58
|
+
@json = nil
|
60
59
|
|
61
60
|
unless do_load || do_dump || do_read || do_write
|
62
61
|
do_load = true
|
@@ -67,72 +66,69 @@ end
|
|
67
66
|
|
68
67
|
# prepare all the formats for input
|
69
68
|
if files.empty?
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
@obj = []
|
70
|
+
@mult.times do
|
71
|
+
@obj << (do_sample ? sample_doc(2) : files('..'))
|
73
72
|
end
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
File.
|
79
|
-
File.
|
80
|
-
File.
|
74
|
+
@mars = Marshal.dump(@obj)
|
75
|
+
@xml = Ox.dump(@obj, :indent => @indent, :circular => @circular)
|
76
|
+
@json = Oj.dump(@obj, :indent => @indent, :circular => @circular, :mode => :object)
|
77
|
+
File.write('sample.xml', @xml)
|
78
|
+
File.write('sample.json', @json)
|
79
|
+
File.write('sample.marshal', @mars)
|
81
80
|
else
|
82
81
|
puts "loading and parsing #{files}\n\n"
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
files.map do |f|
|
83
|
+
@xml = File.read(f)
|
84
|
+
@obj = Ox.load(@xml)
|
85
|
+
@mars = Marshal.dump(@obj)
|
86
|
+
@json = Oj.dump(@obj, :indent => @indent, :circular => @circular)
|
88
87
|
end
|
89
88
|
end
|
90
89
|
|
91
|
-
Oj.default_options = { :mode => :object, :indent =>
|
92
|
-
#puts "json: #{
|
93
|
-
#puts "xml: #{
|
94
|
-
#puts "marshal: #{
|
95
|
-
|
90
|
+
Oj.default_options = { :mode => :object, :indent => @indent, :circular => @circular, :allow_gc => @allow_gc }
|
91
|
+
# puts "json: #{@json.size}"
|
92
|
+
# puts "xml: #{@xml.size}"
|
93
|
+
# puts "marshal: #{@mars.size}"
|
96
94
|
|
97
95
|
if do_load
|
98
96
|
puts '-' * 80
|
99
|
-
puts
|
97
|
+
puts 'Load Performance'
|
100
98
|
perf = Perf.new()
|
101
|
-
perf.add('Oj.object', 'load') { Oj.object_load(
|
102
|
-
perf.add('Ox', 'load') { Ox.load(
|
103
|
-
perf.add('Marshal', 'load') { Marshal.load(
|
104
|
-
perf.run(
|
99
|
+
perf.add('Oj.object', 'load') { Oj.object_load(@json) }
|
100
|
+
perf.add('Ox', 'load') { Ox.load(@xml, :mode => :object) }
|
101
|
+
perf.add('Marshal', 'load') { Marshal.load(@mars) }
|
102
|
+
perf.run(@iter)
|
105
103
|
end
|
106
104
|
|
107
105
|
if do_dump
|
108
106
|
puts '-' * 80
|
109
|
-
puts
|
107
|
+
puts 'Dump Performance'
|
110
108
|
perf = Perf.new()
|
111
|
-
perf.add('Oj', 'dump') { Oj.dump(
|
112
|
-
perf.add('Ox', 'dump') { Ox.dump(
|
113
|
-
perf.add('Marshal', 'dump') { Marshal.dump(
|
114
|
-
perf.run(
|
109
|
+
perf.add('Oj', 'dump') { Oj.dump(@obj) }
|
110
|
+
perf.add('Ox', 'dump') { Ox.dump(@obj, :indent => @indent, :circular => @circular) }
|
111
|
+
perf.add('Marshal', 'dump') { Marshal.dump(@obj) }
|
112
|
+
perf.run(@iter)
|
115
113
|
end
|
116
114
|
|
117
115
|
if do_read
|
118
116
|
puts '-' * 80
|
119
|
-
puts
|
117
|
+
puts 'Read from file Performance'
|
120
118
|
perf = Perf.new()
|
121
119
|
perf.add('Oj', 'load') { Oj.load_file('sample.json') }
|
122
|
-
#perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
|
120
|
+
# perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
|
123
121
|
perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
|
124
122
|
perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
|
125
|
-
perf.run(
|
123
|
+
perf.run(@iter)
|
126
124
|
end
|
127
125
|
|
128
126
|
if do_write
|
129
127
|
puts '-' * 80
|
130
|
-
puts
|
128
|
+
puts 'Write to file Performance'
|
131
129
|
perf = Perf.new()
|
132
|
-
perf.add('Oj', 'to_file') { Oj.to_file('sample.json',
|
133
|
-
perf.add('Ox', 'to_file') { Ox.to_file('sample.xml',
|
134
|
-
perf.add('Marshal', 'dump') { Marshal.dump(
|
135
|
-
perf.run(
|
130
|
+
perf.add('Oj', 'to_file') { Oj.to_file('sample.json', @obj) }
|
131
|
+
perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', @obj, :indent => @indent, :circular => @circular) }
|
132
|
+
perf.add('Marshal', 'dump') { Marshal.dump(@obj, File.new('sample.marshal', 'w')) }
|
133
|
+
perf.run(@iter)
|
136
134
|
end
|
137
|
-
|
138
|
-
|
data/test/perf_once.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'English'
|
5
|
+
$LOAD_PATH << '.'
|
6
|
+
$LOAD_PATH << File.join(__dir__, '../lib')
|
7
|
+
$LOAD_PATH << File.join(__dir__, '../ext')
|
8
|
+
|
9
|
+
require 'oj'
|
10
|
+
|
11
|
+
filename = 'tmp.json'
|
12
|
+
File.open(filename, 'w') { |f|
|
13
|
+
cnt = 0
|
14
|
+
f.puts('{')
|
15
|
+
('a'..'z').each { |a|
|
16
|
+
('a'..'z').each { |b|
|
17
|
+
('a'..'z').each { |c|
|
18
|
+
('a'..'z').each { |d|
|
19
|
+
f.puts(%|"#{a}#{b}#{c}#{d}":#{cnt},|)
|
20
|
+
cnt += 1
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
f.puts('"_last":0}')
|
26
|
+
}
|
27
|
+
|
28
|
+
def mem
|
29
|
+
`ps -o rss= -p #{$PROCESS_ID}`.to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
Oj.default_options = { mode: :strict, cache_keys: false, cache_str: -1 }
|
33
|
+
start = Time.now
|
34
|
+
Oj.load_file('tmp.json')
|
35
|
+
dur = Time.now - start
|
36
|
+
GC.start
|
37
|
+
puts "no cache duration: #{dur} @ #{mem}"
|
38
|
+
|
39
|
+
Oj.default_options = { cache_keys: true }
|
40
|
+
start = Time.now
|
41
|
+
Oj.load_file('tmp.json')
|
42
|
+
dur = Time.now - start
|
43
|
+
GC.start
|
44
|
+
puts "initial cache duration: #{dur} @ #{mem}"
|
45
|
+
|
46
|
+
start = Time.now
|
47
|
+
Oj.load_file('tmp.json')
|
48
|
+
dur = Time.now - start
|
49
|
+
GC.start
|
50
|
+
puts "second cache duration: #{dur} @ #{mem}"
|
51
|
+
|
52
|
+
10.times { GC.start }
|
53
|
+
start = Time.now
|
54
|
+
Oj.load_file('tmp.json')
|
55
|
+
dur = Time.now - start
|
56
|
+
GC.start
|
57
|
+
puts "after several GCs cache duration: #{dur} @ #{mem}"
|
58
|
+
|
59
|
+
# TBD check memory use
|
data/test/perf_parser.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH << '.'
|
5
|
+
$LOAD_PATH << File.join(__dir__, '../lib')
|
6
|
+
$LOAD_PATH << File.join(__dir__, '../ext')
|
7
|
+
|
8
|
+
require 'optparse'
|
9
|
+
require 'perf'
|
10
|
+
require 'oj'
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
$verbose = false
|
14
|
+
$iter = 50_000
|
15
|
+
$with_bignum = false
|
16
|
+
$size = 1
|
17
|
+
$cache_keys = true
|
18
|
+
$symbol_keys = false
|
19
|
+
|
20
|
+
opts = OptionParser.new
|
21
|
+
opts.on('-v', 'verbose') { $verbose = true }
|
22
|
+
opts.on('-c', '--count [Int]', Integer, 'iterations') { |i| $iter = i }
|
23
|
+
opts.on('-s', '--size [Int]', Integer, 'size (~Kbytes)') { |i| $size = i }
|
24
|
+
opts.on('-b', 'with bignum') { $with_bignum = true }
|
25
|
+
opts.on('-k', 'no cache') { $cache_keys = false }
|
26
|
+
opts.on('-sym', 'symbol keys') { $symbol_keys = true }
|
27
|
+
opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
|
28
|
+
opts.parse(ARGV)
|
29
|
+
|
30
|
+
$obj = {
|
31
|
+
'a' => 'Alpha', # string
|
32
|
+
'b' => true, # boolean
|
33
|
+
'c' => 12_345, # number
|
34
|
+
'd' => [ true, [false, [-123_456_789, nil], 3.9676, ['Something else.', false, 1, nil], nil]], # mix it up array
|
35
|
+
'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
|
36
|
+
'f' => nil, # nil
|
37
|
+
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
38
|
+
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
39
|
+
}
|
40
|
+
$obj['g'] = 12_345_678_901_234_567_890_123_456_789 if $with_bignum
|
41
|
+
|
42
|
+
if 0 < $size
|
43
|
+
o = $obj
|
44
|
+
$obj = []
|
45
|
+
(4 * $size).times do
|
46
|
+
$obj << o
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
$json = Oj.dump($obj)
|
51
|
+
$failed = {} # key is same as String used in tests later
|
52
|
+
Oj.default_options = {create_id: '^', create_additions: true, class_cache: true}
|
53
|
+
Oj.default_options = if $cache_keys
|
54
|
+
{cache_keys: true, cache_str: 6, symbol_keys: $symbol_keys}
|
55
|
+
else
|
56
|
+
{cache_keys: false, cache_str: -1, symbol_keys: $symbol_keys}
|
57
|
+
end
|
58
|
+
JSON.parser = JSON::Ext::Parser
|
59
|
+
|
60
|
+
class AllSaj
|
61
|
+
|
62
|
+
def hash_start(key)
|
63
|
+
end
|
64
|
+
|
65
|
+
def hash_end(key)
|
66
|
+
end
|
67
|
+
|
68
|
+
def array_start(key)
|
69
|
+
end
|
70
|
+
|
71
|
+
def array_end(key)
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_value(value, key)
|
75
|
+
end
|
76
|
+
end # AllSaj
|
77
|
+
|
78
|
+
no_handler = Object.new()
|
79
|
+
all_handler = AllSaj.new()
|
80
|
+
|
81
|
+
if $verbose
|
82
|
+
puts "json:\n#{$json}\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
### Validate ######################
|
86
|
+
p_val = Oj::Parser.new(:validate)
|
87
|
+
|
88
|
+
puts '-' * 80
|
89
|
+
puts 'Validate Performance'
|
90
|
+
perf = Perf.new()
|
91
|
+
perf.add('Oj::Parser.validate', 'none') { p_val.parse($json) }
|
92
|
+
perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_handler, $json) }
|
93
|
+
perf.run($iter)
|
94
|
+
|
95
|
+
### SAJ ######################
|
96
|
+
p_all = Oj::Parser.new(:saj)
|
97
|
+
p_all.handler = all_handler
|
98
|
+
p_all.cache_keys = $cache_keys
|
99
|
+
p_all.cache_strings = 6
|
100
|
+
|
101
|
+
puts '-' * 80
|
102
|
+
puts 'Parse Callback Performance'
|
103
|
+
perf = Perf.new()
|
104
|
+
perf.add('Oj::Parser.saj', 'all') { p_all.parse($json) }
|
105
|
+
perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(all_handler, $json) }
|
106
|
+
perf.run($iter)
|
107
|
+
|
108
|
+
### Usual ######################
|
109
|
+
p_usual = Oj::Parser.new(:usual)
|
110
|
+
p_usual.cache_keys = $cache_keys
|
111
|
+
p_usual.cache_strings = ($cache_keys ? 6 : 0)
|
112
|
+
p_usual.symbol_keys = $symbol_keys
|
113
|
+
|
114
|
+
puts '-' * 80
|
115
|
+
puts 'Parse Usual Performance'
|
116
|
+
perf = Perf.new()
|
117
|
+
perf.add('Oj::Parser.usual', '') { p_usual.parse($json) }
|
118
|
+
perf.add('Oj::strict_load', '') { Oj.strict_load($json) }
|
119
|
+
perf.add('JSON::Ext', 'parse') { JSON.parse($json) }
|
120
|
+
perf.run($iter)
|
121
|
+
|
122
|
+
### Usual Objects ######################
|
123
|
+
|
124
|
+
# Original Oj follows the JSON gem for creating objects which uses the class
|
125
|
+
# json_create(arg) method. Oj::Parser in usual mode supprts the same but also
|
126
|
+
# handles populating the object variables directly which is faster.
|
127
|
+
|
128
|
+
class Stuff
|
129
|
+
attr_accessor :alpha, :bravo, :charlie, :delta, :echo, :foxtrot, :golf, :hotel, :india, :juliet
|
130
|
+
|
131
|
+
def self.json_create(arg)
|
132
|
+
obj = new
|
133
|
+
obj.alpha = arg['alpha']
|
134
|
+
obj.bravo = arg['bravo']
|
135
|
+
obj.charlie = arg['charlie']
|
136
|
+
obj.delta = arg['delta']
|
137
|
+
obj.echo = arg['echo']
|
138
|
+
obj.foxtrot = arg['foxtrot']
|
139
|
+
obj.golf = arg['golf']
|
140
|
+
obj.hotel = arg['hotel']
|
141
|
+
obj.india = arg['india']
|
142
|
+
obj.juliet = arg['juliet']
|
143
|
+
obj
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
$obj_json = %|{
|
148
|
+
"alpha": [0, 1,2,3,4,5,6,7,8,9],
|
149
|
+
"bravo": true,
|
150
|
+
"charlie": 123,
|
151
|
+
"delta": "some string",
|
152
|
+
"echo": null,
|
153
|
+
"^": "Stuff",
|
154
|
+
"foxtrot": false,
|
155
|
+
"golf": "gulp",
|
156
|
+
"hotel": {"x": true, "y": false},
|
157
|
+
"india": [null, true, 123],
|
158
|
+
"juliet": "junk"
|
159
|
+
}|
|
160
|
+
|
161
|
+
p_usual = Oj::Parser.new(:usual)
|
162
|
+
p_usual.cache_keys = $cache_keys
|
163
|
+
p_usual.cache_strings = ($cache_keys ? 6 : 0)
|
164
|
+
p_usual.symbol_keys = $symbol_keys
|
165
|
+
p_usual.create_id = '^'
|
166
|
+
p_usual.class_cache = true
|
167
|
+
p_usual.ignore_json_create = true
|
168
|
+
|
169
|
+
JSON.create_id = '^'
|
170
|
+
|
171
|
+
puts '-' * 80
|
172
|
+
puts 'Parse Usual Object Performance'
|
173
|
+
perf = Perf.new()
|
174
|
+
perf.add('Oj::Parser.usual', '') { p_usual.parse($obj_json) }
|
175
|
+
perf.add('Oj::compat_load', '') { Oj.compat_load($obj_json) }
|
176
|
+
perf.add('JSON::Ext', 'parse') { JSON.parse($obj_json) }
|
177
|
+
|
178
|
+
perf.run($iter)
|
179
|
+
|
180
|
+
unless $failed.empty?
|
181
|
+
puts 'The following packages were not included for the reason listed'
|
182
|
+
$failed.each { |tag, msg| puts "***** #{tag}: #{msg}" }
|
183
|
+
end
|
data/test/perf_saj.rb
CHANGED
@@ -1,40 +1,37 @@
|
|
1
1
|
#!/usr/bin/env ruby -wW1
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
$LOAD_PATH << '.'
|
5
|
+
$LOAD_PATH << File.join(__dir__, '../lib')
|
6
|
+
$LOAD_PATH << File.join(__dir__, '../ext')
|
7
7
|
|
8
8
|
require 'optparse'
|
9
|
-
require 'yajl'
|
9
|
+
# require 'yajl'
|
10
10
|
require 'perf'
|
11
11
|
require 'json'
|
12
12
|
require 'json/ext'
|
13
13
|
require 'oj'
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
@verbose = false
|
16
|
+
@indent = 0
|
17
|
+
@iter = 10_000
|
18
|
+
@gets = 0
|
19
|
+
@fetch = false
|
20
|
+
@write = false
|
21
|
+
@read = false
|
22
22
|
|
23
23
|
opts = OptionParser.new
|
24
|
-
opts.on(
|
25
|
-
opts.on(
|
26
|
-
opts.on(
|
27
|
-
opts.on(
|
28
|
-
opts.on(
|
29
|
-
opts.on(
|
30
|
-
opts.on(
|
31
|
-
opts.on(
|
32
|
-
|
24
|
+
opts.on('-v', 'verbose') { @verbose = true }
|
25
|
+
opts.on('-c', '--count [Int]', Integer, 'iterations') { |i| @iter = i }
|
26
|
+
opts.on('-i', '--indent [Int]', Integer, 'indentation') { |i| @indent = i }
|
27
|
+
opts.on('-g', '--gets [Int]', Integer, 'number of gets') { |i| @gets = i }
|
28
|
+
opts.on('-f', 'fetch') { @fetch = true }
|
29
|
+
opts.on('-w', 'write') { @write = true }
|
30
|
+
opts.on('-r', 'read') { @read = true }
|
31
|
+
opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
|
32
|
+
opts.parse(ARGV)
|
33
33
|
|
34
34
|
class AllSaj < Oj::Saj
|
35
|
-
def initialize()
|
36
|
-
end
|
37
|
-
|
38
35
|
def hash_start(key)
|
39
36
|
end
|
40
37
|
|
@@ -52,58 +49,53 @@ class AllSaj < Oj::Saj
|
|
52
49
|
end # AllSaj
|
53
50
|
|
54
51
|
class NoSaj < Oj::Saj
|
55
|
-
def initialize()
|
56
|
-
end
|
57
52
|
end # NoSaj
|
58
53
|
|
59
54
|
saj_handler = AllSaj.new()
|
60
55
|
no_saj = NoSaj.new()
|
61
56
|
|
62
|
-
|
57
|
+
@obj = {
|
63
58
|
'a' => 'Alpha', # string
|
64
59
|
'b' => true, # boolean
|
65
|
-
'c' =>
|
66
|
-
'd' => [ true, [false, {'12345' =>
|
60
|
+
'c' => 12_345, # number
|
61
|
+
'd' => [ true, [false, {'12345' => 12_345, 'nil' => nil}, 3.967, { 'x' => 'something', 'y' => false, 'z' => true}, nil]], # mix it up array
|
67
62
|
'e' => { 'one' => 1, 'two' => 2 }, # hash
|
68
63
|
'f' => nil, # nil
|
69
|
-
'g' =>
|
64
|
+
'g' => 12_345_678_901_234_567_890_123_456_789, # big number
|
70
65
|
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
71
66
|
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
72
67
|
}
|
73
68
|
|
74
|
-
Oj.default_options = { :indent =>
|
69
|
+
Oj.default_options = { :indent => @indent, :mode => :compat }
|
75
70
|
|
76
|
-
|
77
|
-
|
71
|
+
@json = Oj.dump(@obj)
|
72
|
+
@failed = {} # key is same as String used in tests later
|
78
73
|
|
79
74
|
def capture_error(tag, orig, load_key, dump_key, &blk)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
$failed[tag] = "#{e.class}: #{e.message}"
|
85
|
-
end
|
75
|
+
obj = blk.call(orig)
|
76
|
+
raise "#{tag} #{dump_key} and #{load_key} did not return the same object as the original." unless orig == obj
|
77
|
+
rescue Exception => e
|
78
|
+
@failed[tag] = "#{e.class}: #{e.message}"
|
86
79
|
end
|
87
80
|
|
88
81
|
# Verify that all packages dump and load correctly and return the same Object as the original.
|
89
|
-
capture_error('Yajl',
|
90
|
-
capture_error('JSON::Ext',
|
82
|
+
# capture_error('Yajl', @obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
|
83
|
+
capture_error('JSON::Ext', @obj, 'generate', 'parse') { |o| JSON.generator = JSON::Ext::Generator; JSON::Ext::Parser.new(JSON.generate(o)).parse }
|
91
84
|
|
92
|
-
if
|
93
|
-
puts "json:\n#{
|
85
|
+
if @verbose
|
86
|
+
puts "json:\n#{@json}\n"
|
94
87
|
end
|
95
88
|
|
96
|
-
|
97
89
|
puts '-' * 80
|
98
|
-
puts
|
90
|
+
puts 'Parse Performance'
|
99
91
|
perf = Perf.new()
|
100
|
-
perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler,
|
101
|
-
perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj,
|
102
|
-
perf.add('Yajl', 'parse') { Yajl::Parser.parse(
|
103
|
-
perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new(
|
104
|
-
perf.run(
|
105
|
-
|
106
|
-
unless
|
107
|
-
puts
|
108
|
-
|
92
|
+
perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, @json) }
|
93
|
+
perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, @json) }
|
94
|
+
# perf.add('Yajl', 'parse') { Yajl::Parser.parse(@json) } unless @failed.has_key?('Yajl')
|
95
|
+
perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new(@json).parse } unless @failed.key?('JSON::Ext')
|
96
|
+
perf.run(@iter)
|
97
|
+
|
98
|
+
unless @failed.empty?
|
99
|
+
puts 'The following packages were not included for the reason listed'
|
100
|
+
@failed.each { |tag, msg| puts "***** #{tag}: #{msg}" }
|
109
101
|
end
|