oj 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

@@ -45,6 +45,8 @@ extern "C" {
45
45
  #include "ruby/encoding.h"
46
46
  #endif
47
47
 
48
+ #include "cache.h"
49
+
48
50
  #ifdef JRUBY
49
51
  #define NO_RSTRUCT 1
50
52
  #endif
@@ -90,12 +92,20 @@ extern void _oj_raise_error(const char *msg, const char *xml, const char *curren
90
92
 
91
93
  extern VALUE Oj;
92
94
 
95
+ extern VALUE oj_time_class;
96
+
97
+ extern ID oj_at_id;
93
98
  extern ID oj_instance_variables_id;
94
99
  extern ID oj_to_hash_id;
95
100
  extern ID oj_to_json_id;
101
+ extern ID oj_to_sym_id;
102
+ extern ID oj_tv_nsec_id;
96
103
  extern ID oj_tv_sec_id;
97
104
  extern ID oj_tv_usec_id;
98
105
 
106
+ extern Cache oj_class_cache;
107
+ extern Cache oj_attr_cache;
108
+
99
109
  #if defined(__cplusplus)
100
110
  #if 0
101
111
  { /* satisfy cc-mode */
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby -wW2
2
+
3
+ if $0 == __FILE__
4
+ $: << '.'
5
+ $: << '..'
6
+ $: << '../lib'
7
+ $: << '../ext'
8
+ end
9
+
10
+ require 'pp'
11
+ require 'sample/file'
12
+ require 'sample/dir'
13
+
14
+ def files(dir)
15
+ d = ::Sample::Dir.new(dir)
16
+ Dir.new(dir).each do |fn|
17
+ next if fn.start_with?('.')
18
+ filename = File.join(dir, fn)
19
+ #filename = '.' == dir ? fn : File.join(dir, fn)
20
+ if File.directory?(filename)
21
+ d << files(filename)
22
+ else
23
+ d << ::Sample::File.new(filename)
24
+ end
25
+ end
26
+ #pp d
27
+ d
28
+ end
29
+
@@ -0,0 +1,106 @@
1
+
2
+ class Perf
3
+
4
+ def initialize()
5
+ @items = []
6
+ end
7
+
8
+ def add(title, op, &blk)
9
+ @items << Item.new(title, op, &blk)
10
+ end
11
+
12
+ def before(title, &blk)
13
+ @items.each do |i|
14
+ if title == i.title
15
+ i.set_before(&blk)
16
+ break
17
+ end
18
+ end
19
+ end
20
+
21
+ def run(iter)
22
+ base = Item.new(nil, nil) { }
23
+ base.run(iter, 0.0)
24
+ @items.each do |i|
25
+ i.run(iter, base.duration)
26
+ if i.error.nil?
27
+ puts "#{i.title}.#{i.op} #{iter} times in %0.3f seconds or %0.3f #{i.op}/sec." % [i.duration, iter / i.duration]
28
+ else
29
+ puts "***** #{i.title}.#{i.op} failed! #{i.error}"
30
+ end
31
+ end
32
+ summary()
33
+ end
34
+
35
+ def summary()
36
+ fastest = nil
37
+ slowest = nil
38
+ width = 6
39
+ @items.each do |i|
40
+ next if i.duration.nil?
41
+ width = i.title.size if width < i.title.size
42
+ end
43
+ iva = @items.clone
44
+ iva.delete_if { |i| i.duration.nil? }
45
+ iva.sort_by! { |i| i.duration }
46
+ puts
47
+ puts "Summary:"
48
+ puts "%*s time (secs) rate (ops/sec)" % [width, 'System']
49
+ puts "#{'-' * width} ----------- --------------"
50
+ iva.each do |i|
51
+ if i.duration.nil?
52
+ else
53
+ puts "%*s %11.3f %14.3f" % [width, i.title, i.duration, i.rate ]
54
+ end
55
+ end
56
+ puts
57
+ puts "Comparison Matrix\n(performance factor, 2.0 row is means twice as fast as column)"
58
+ puts ([' ' * width] + iva.map { |i| "%*s" % [width, i.title] }).join(' ')
59
+ puts (['-' * width] + iva.map { |i| '-' * width }).join(' ')
60
+ iva.each do |i|
61
+ line = ["%*s" % [width, i.title]]
62
+ iva.each do |o|
63
+ line << "%*.2f" % [width, o.duration / i.duration]
64
+ end
65
+ puts line.join(' ')
66
+ end
67
+ puts
68
+ end
69
+
70
+ class Item
71
+ attr_accessor :title
72
+ attr_accessor :op
73
+ attr_accessor :blk
74
+ attr_accessor :duration
75
+ attr_accessor :rate
76
+ attr_accessor :error
77
+
78
+ def initialize(title, op, &blk)
79
+ @title = title
80
+ @blk = blk
81
+ @op = op
82
+ @duration = nil
83
+ @rate = nil
84
+ @error = nil
85
+ @before = nil
86
+ end
87
+
88
+ def set_before(&blk)
89
+ @before = blk
90
+ end
91
+
92
+ def run(iter, base)
93
+ begin
94
+ @before.call unless @before.nil?
95
+ start = Time.now
96
+ iter.times { @blk.call }
97
+ @duration = Time.now - start - base
98
+ @duration = 0.0 if @duration < 0.0
99
+ @rate = iter / @duration
100
+ rescue Exception => e
101
+ @error = "#{e.class}: #{e.message}"
102
+ end
103
+ end
104
+
105
+ end # Item
106
+ end # Perf
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '.'
4
+ $: << '../lib'
5
+ $: << '../ext'
6
+
7
+ if __FILE__ == $0
8
+ if (i = ARGV.index('-I'))
9
+ x,path = ARGV.slice!(i, 2)
10
+ $: << path
11
+ end
12
+ end
13
+
14
+ require 'optparse'
15
+ require 'ox'
16
+ require 'oj'
17
+ require 'perf'
18
+ require 'sample'
19
+ require 'files'
20
+
21
+ $circular = false
22
+ $indent = 0
23
+
24
+ do_sample = false
25
+ do_files = false
26
+
27
+ do_load = false
28
+ do_dump = false
29
+ do_read = false
30
+ do_write = false
31
+ $iter = 1000
32
+
33
+ opts = OptionParser.new
34
+ opts.on("-c", "circular options") { $circular = true }
35
+
36
+ opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
37
+ opts.on("-f", "load and dump as files Ruby object") { do_files = true }
38
+
39
+ opts.on("-l", "load") { do_load = true }
40
+ opts.on("-d", "dump") { do_dump = true }
41
+ opts.on("-r", "read") { do_read = true }
42
+ opts.on("-w", "write") { do_write = true }
43
+ opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
44
+
45
+ opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
46
+
47
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
48
+ files = opts.parse(ARGV)
49
+
50
+ $obj = nil
51
+ $xml = nil
52
+ $mars = nil
53
+ $json = nil
54
+
55
+ unless do_load || do_dump || do_read || do_write
56
+ do_load = true
57
+ do_dump = true
58
+ do_read = true
59
+ do_write = true
60
+ end
61
+
62
+ # prepare all the formats for input
63
+ if files.empty?
64
+ $obj = do_sample ? sample_doc(2) : files('..')
65
+ $mars = Marshal.dump($obj)
66
+ $xml = Ox.dump($obj, :indent => $indent, circular: $circular)
67
+ $json = Oj.dump($obj, :indent => $indent, circular: $circular)
68
+ File.open('sample.xml', 'w') { |f| f.write($xml) }
69
+ File.open('sample.json', 'w') { |f| f.write($json) }
70
+ File.open('sample.marshal', 'w') { |f| f.write($mars) }
71
+ else
72
+ puts "loading and parsing #{files}\n\n"
73
+ # TBD change to allow xml and json
74
+ data = files.map do |f|
75
+ $xml = File.read(f)
76
+ $obj = Ox.load($xml);
77
+ $mars = Marshal.dump($obj)
78
+ $json = Oj.dump($obj, :indent => $indent, circular: $circular)
79
+ end
80
+ end
81
+
82
+ Oj.default_options = { :mode => :object, :indent => $indent }
83
+
84
+ if do_load
85
+ puts '-' * 80
86
+ puts "Load Performance"
87
+ perf = Perf.new()
88
+ perf.add('Ox', 'load') { Ox.load($xml, :mode => :object) }
89
+ perf.add('Oj', 'load') { Oj.load($json) }
90
+ perf.add('Marshal', 'load') { Marshal.load($mars) }
91
+ perf.run($iter)
92
+ end
93
+
94
+ if do_dump
95
+ puts '-' * 80
96
+ puts "Dump Performance"
97
+ perf = Perf.new()
98
+ perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
99
+ perf.add('Oj', 'dump') { Oj.dump($obj) }
100
+ perf.add('Marshal', 'dump') { Marshal.dump($obj) }
101
+ perf.run($iter)
102
+ end
103
+
104
+ if do_read
105
+ puts '-' * 80
106
+ puts "Read from file Performance"
107
+ perf = Perf.new()
108
+ perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
109
+ perf.add('Oj', 'load') { Oj.load_file('sample.json') }
110
+ perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
111
+ perf.run($iter)
112
+ end
113
+
114
+ if do_write
115
+ puts '-' * 80
116
+ puts "Write to file Performance"
117
+ perf = Perf.new()
118
+ perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', $obj, :indent => $indent, :circular => $circular) }
119
+ perf.add('Oj', 'to_file') { Oj.to_file('sample.json', $obj) }
120
+ perf.add('Marshal', 'dump') { Marshal.dump($obj, File.new('sample.marshal', 'w')) }
121
+ perf.run($iter)
122
+ end
123
+
124
+
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env ruby -wW1
2
+ # encoding: UTF-8
3
+
4
+ $: << '.'
5
+ $: << File.join(File.dirname(__FILE__), "../lib")
6
+ $: << File.join(File.dirname(__FILE__), "../ext")
7
+
8
+ require 'optparse'
9
+ require 'yajl'
10
+ require 'perf'
11
+ require 'json'
12
+ require 'json/pure'
13
+ require 'json/ext'
14
+ require 'msgpack'
15
+ require 'oj'
16
+ require 'ox'
17
+
18
+ class Jazz
19
+ def initialize()
20
+ @boolean = true
21
+ @number = 58
22
+ @string = "A string"
23
+ @array = [true, false, nil]
24
+ @hash = { 'one' => 1, 'two' => 2 }
25
+ end
26
+ def to_json(*) # Yajl and JSON have different signatures
27
+ %{
28
+ { "boolean":#{@boolean},
29
+ "number":#{@number},
30
+ "string":#{@string},
31
+ "array":#{@array},
32
+ "hash":#{@hash},
33
+ }
34
+ }
35
+ end
36
+ def to_hash()
37
+ { 'boolean' => @boolean,
38
+ 'number' => @number,
39
+ 'string' => @string,
40
+ 'array' => @array,
41
+ 'hash' => @hash,
42
+ }
43
+ end
44
+ def to_msgpack(out)
45
+ out << MessagePack.pack(to_hash())
46
+ end
47
+ end
48
+
49
+ $indent = 0
50
+ $iter = 100000
51
+ $with_object = true
52
+ $with_bignum = true
53
+ $with_nums = true
54
+
55
+ opts = OptionParser.new
56
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
57
+ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
58
+ opts.on("-o", "without objects") { $with_object = false }
59
+ opts.on("-b", "without bignum") { $with_bignum = false }
60
+ opts.on("-n", "without numbers") { $with_nums = false }
61
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
62
+ files = opts.parse(ARGV)
63
+
64
+ if $with_nums
65
+ $obj = {
66
+ 'a' => 'Alpha',
67
+ 'b' => true,
68
+ 'c' => 12345,
69
+ 'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]],
70
+ 'e' => { 'one' => 1, 'two' => 2 },
71
+ 'f' => nil,
72
+ }
73
+ $obj['g'] = Jazz.new() if $with_object
74
+ $obj['h'] = 12345678901234567890123456789 if $with_bignum
75
+ else
76
+ $obj = {
77
+ 'a' => 'Alpha',
78
+ 'b' => true,
79
+ 'c' => '12345',
80
+ 'd' => [ true, [false, ['12345', nil], '3.967', ['something', false], nil]],
81
+ 'e' => { 'one' => '1', 'two' => '2' },
82
+ 'f' => nil,
83
+ }
84
+ end
85
+
86
+ Oj.default_options = { :indent => $indent, :mode => :compat }
87
+ Ox.default_options = { :indent => $indent, :mode => :object }
88
+
89
+ $json = Oj.dump($obj)
90
+ $xml = Ox.dump($obj, :indent => $indent)
91
+ begin
92
+ $msgpack = MessagePack.pack($obj)
93
+ rescue Exception => e
94
+ puts "MessagePack failed to pack! #{e.class}: #{e.message}.\nSkipping."
95
+ $msgpack = nil
96
+ end
97
+
98
+ puts '-' * 80
99
+ puts "Load/Parse Performance"
100
+ perf = Perf.new()
101
+ perf.add('Oj', 'load') { Oj.load($json) }
102
+ perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) }
103
+ perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse }
104
+ perf.add('JSON::Pure', 'parse') { JSON::Pure::Parser.new($json).parse }
105
+ perf.add('Ox', 'load') { Ox.load($xml) }
106
+ perf.add('MessagePack', 'unpack') { MessagePack.unpack($msgpack) } unless $msgpack.nil?
107
+ perf.run($iter)
108
+
109
+ puts
110
+ puts '-' * 80
111
+ puts "Dump/Encode/Generate Performance"
112
+ perf = Perf.new()
113
+ perf.add('Oj', 'dump') { Oj.dump($obj) }
114
+ perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) }
115
+ if 0 == $indent
116
+ perf.add('JSON::Ext', 'generate') { JSON.generate($obj) }
117
+ else
118
+ perf.add('JSON::Ext', 'generate') { JSON.pretty_generate($obj) }
119
+ end
120
+ perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
121
+ if 0 == $indent
122
+ perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
123
+ else
124
+ perf.add('JSON::Pure', 'generate') { JSON.pretty_generate($obj) }
125
+ end
126
+ perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator }
127
+ perf.add('Ox', 'dump') { Ox.dump($obj) }
128
+ perf.add('MessagePack', 'pack') { MessagePack.pack($obj) } unless $msgpack.nil?
129
+ perf.run($iter)
130
+
131
+ puts
@@ -8,30 +8,48 @@ if $0 == __FILE__
8
8
  end
9
9
 
10
10
  require 'pp'
11
- require 'oj'
11
+ require 'sample/doc'
12
12
 
13
- def sample_json(size=3)
13
+
14
+ def sample_doc(size=3)
14
15
  colors = [ :black, :gray, :white, :red, :blue, :yellow, :green, :purple, :orange ]
15
- container = []
16
- size.times do |i|
17
- box = {
18
- 'color' => colors[i % colors.size],
19
- 'fragile' => (0 == (i % 2)),
20
- 'width' => i,
21
- 'height' => i,
22
- 'depth' => i,
23
- 'weight' => i * 1.3,
24
- 'address' => {
25
- 'street' => "#{i} Main Street",
26
- 'city' => 'Sity',
27
- 'state' => nil
28
- }
29
- }
30
- container << box
16
+
17
+ d = ::Sample::Doc.new('Sample')
18
+
19
+ # add some history
20
+ (0..size * 10).each do |i|
21
+ d.add_change("Changed at t+#{i}.")
31
22
  end
32
- container
33
- end
34
23
 
35
- if $0 == __FILE__
36
- File.open('sample.json', "w") { |f| f.write(Oj.dump(sample_json(3), :indent => 2)) }
24
+ # add some layers
25
+ (1..size).each do |i|
26
+ layer = ::Sample::Layer.new("Layer-#{i}")
27
+ (1..size).each do |j|
28
+ g = ::Sample::Group.new
29
+ (1..size).each do |k|
30
+ g2 = ::Sample::Group.new
31
+ r = ::Sample::Rect.new(j * 40 + 10.0, i * 10.0,
32
+ 10.123456 / k, 10.0 / k, colors[(i + j + k) % colors.size])
33
+ r.add_prop(:part_of, layer.name)
34
+ g2 << r
35
+ g2 << ::Sample::Text.new("#{k} in #{j}", r.left, r.top, r.width, r.height)
36
+ g << g2
37
+ end
38
+ g2 = ::Sample::Group.new
39
+ (1..size).each do |k|
40
+ o = ::Sample::Oval.new(j * 40 + 12.0, i * 10.0 + 2.0,
41
+ 6.0 / k, 6.0 / k, colors[(i + j + k) % colors.size])
42
+ o.add_prop(:inside, true)
43
+ g << o
44
+ end
45
+ g << g2
46
+ layer << g
47
+ end
48
+ d.layers[layer.name] = layer
49
+ end
50
+
51
+ # some properties
52
+ d.add_prop(:purpose, 'an example')
53
+
54
+ d
37
55
  end