Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize JSON::Pure::Generator by 2x-4x for simple options cases #586

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion lib/json/pure/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ def configure(opts)
opts.each do |key, value|
instance_variable_set "@#{key}", value
end

# NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json
@indent = opts[:indent] if opts.key?(:indent)
@space = opts[:space] if opts.key?(:space)
@space_before = opts[:space_before] if opts.key?(:space_before)
Expand Down Expand Up @@ -286,12 +288,70 @@ def to_h
# created this method raises a
# GeneratorError exception.
def generate(obj)
result = obj.to_json(self)
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
!@ascii_only and !@script_safe and @max_nesting == 0 and !@strict
result = generate_json(obj, '')
else
result = obj.to_json(self)
end
JSON.valid_utf8?(result) or raise GeneratorError,
"source sequence #{result.inspect} is illegal/malformed utf-8"
result
end

# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
private def generate_json(obj, buf)
case obj
when Hash
buf << '{'.freeze
first = true
eregon marked this conversation as resolved.
Show resolved Hide resolved
obj.each_pair do |k,v|
buf << ','.freeze unless first
fast_serialize_string(k.to_s, buf)
buf << ':'.freeze
generate_json(v, buf)
first = false
end
buf << '}'.freeze
when Array
buf << '['.freeze
first = true
obj.each do |e|
buf << ','.freeze unless first
generate_json(e, buf)
first = false
end
buf << ']'.freeze
when String
fast_serialize_string(obj, buf)
when Integer
buf << obj.to_s
else
# Note: Float is handled this way since it is Float#to_s is slow anyway
buf << obj.to_json(self)
end
end

# Assumes !@ascii_only, !@script_safe
if Regexp.method_defined?(:match?)
private def fast_serialize_string(string, buf) # :nodoc:
buf << '"'.freeze
string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8

if /["\\\x0-\x1f]/n.match?(string)
buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
else
buf << string
end
buf << '"'.freeze
end
else
# Ruby 2.3 compatibility
private def fast_serialize_string(string, buf) # :nodoc:
buf << string.to_json(self)
end
end

# Return the value returned by method +name+.
def [](name)
if respond_to?(name)
Expand Down
Loading