Skip to content

Commit

Permalink
Speedup #generate_json by using case/when/end
Browse files Browse the repository at this point in the history
* if/elsif comparing `obj.class` is significantly slower:
  ruby#668 (comment)
* The only case where an exact class check is needed so far is for String (ruby#667).
* Before: $ ruby -Ilib:ext benchmark/standalone.rb dump pure
JSON::Pure::Generator
truffleruby 24.2.0-dev-07b978e4, like ruby 3.2.4, Oracle GraalVM JVM [x86_64-linux]
Calculating -------------------------------------
      JSON.dump(obj)      6.426k (± 5.9%) i/s  (155.62 μs/i) -     32.395k in   5.064479s
      JSON.dump(obj)      6.380k (± 7.4%) i/s  (156.73 μs/i) -     31.806k in   5.021304s
      JSON.dump(obj)      6.276k (±10.5%) i/s  (159.33 μs/i) -     31.217k in   5.060762s
      JSON.dump(obj)      6.450k (± 7.0%) i/s  (155.05 μs/i) -     32.395k in   5.059538s
      JSON.dump(obj)      6.413k (± 6.2%) i/s  (155.93 μs/i) -     32.395k in   5.081573s
* After: $ ruby -Ilib:ext benchmark/standalone.rb dump pure
JSON::Pure::Generator
truffleruby 24.2.0-dev-07b978e4, like ruby 3.2.4, Oracle GraalVM JVM [x86_64-linux]
Calculating -------------------------------------
      JSON.dump(obj)      8.237k (± 5.0%) i/s  (121.41 μs/i) -     41.600k in   5.069507s
      JSON.dump(obj)      8.179k (± 5.1%) i/s  (122.26 μs/i) -     40.768k in   5.002035s
      JSON.dump(obj)      8.147k (± 7.9%) i/s  (122.74 μs/i) -     40.768k in   5.044840s
      JSON.dump(obj)      8.137k (± 6.9%) i/s  (122.90 μs/i) -     40.768k in   5.048690s
      JSON.dump(obj)      8.112k (±10.2%) i/s  (123.27 μs/i) -     39.936k in   5.023502s
  • Loading branch information
eregon committed Nov 4, 2024
1 parent a9bc48e commit 1da4955
Showing 1 changed file with 16 additions and 14 deletions.
30 changes: 16 additions & 14 deletions lib/json/pure/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,20 +307,18 @@ def generate(obj)

# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
private def generate_json(obj, buf)
klass = obj.class
if klass == Hash
case obj
when Hash
buf << '{'
first = true
obj.each_pair do |k,v|
buf << ',' unless first

key_str = k.to_s
if key_str.is_a?(::String)
if key_str.class == ::String
fast_serialize_string(key_str, buf)
else
generate_json(key_str, buf)
end
if key_str.class == String
fast_serialize_string(key_str, buf)
elsif key_str.is_a?(String)
generate_json(key_str, buf)
else
raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String"
end
Expand All @@ -330,7 +328,7 @@ def generate(obj)
first = false
end
buf << '}'
elsif klass == Array
when Array
buf << '['
first = true
obj.each do |e|
Expand All @@ -339,9 +337,13 @@ def generate(obj)
first = false
end
buf << ']'
elsif klass == String
fast_serialize_string(obj, buf)
elsif klass == Integer
when String
if obj.class == String
fast_serialize_string(obj, buf)
else
buf << obj.to_json(self)
end
when Integer
buf << obj.to_s
else
# Note: Float is handled this way since Float#to_s is slow anyway
Expand Down Expand Up @@ -432,8 +434,8 @@ def json_transform(state)
result << state.indent * depth if indent

key_str = key.to_s
key_json = if key_str.is_a?(::String)
key_str = key_str.to_json(state)
if key_str.is_a?(String)
key_json = key_str.to_json(state)
else
raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
end
Expand Down

0 comments on commit 1da4955

Please sign in to comment.