mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 15:06:10 +02:00

If we assume that most of the time the `opts` hash is small it's faster to go over the provided keys with a `case` than to test all possible keys one by one. Before: ``` == Encoding small nested array (121 bytes) ruby 3.4.0preview2 (2024-10-07 master32c733f57b
) +YJIT +PRISM [arm64-darwin23] Warming up -------------------------------------- json 156.832k i/100ms oj 209.769k i/100ms rapidjson 162.922k i/100ms Calculating ------------------------------------- json 1.599M (± 2.5%) i/s (625.34 ns/i) - 7.998M in 5.005110s oj 2.137M (± 1.5%) i/s (467.99 ns/i) - 10.698M in 5.007806s rapidjson 1.677M (± 3.5%) i/s (596.31 ns/i) - 8.472M in 5.059515s Comparison: json: 1599141.2 i/s oj: 2136785.3 i/s - 1.34x faster rapidjson: 1676977.2 i/s - same-ish: difference falls within error == Encoding small hash (65 bytes) ruby 3.4.0preview2 (2024-10-07 master32c733f57b
) +YJIT +PRISM [arm64-darwin23] Warming up -------------------------------------- json 216.464k i/100ms oj 661.328k i/100ms rapidjson 324.434k i/100ms Calculating ------------------------------------- json 2.301M (± 1.7%) i/s (434.57 ns/i) - 11.689M in 5.081278s oj 7.244M (± 1.2%) i/s (138.05 ns/i) - 36.373M in 5.021985s rapidjson 3.323M (± 2.9%) i/s (300.96 ns/i) - 16.871M in 5.081696s Comparison: json: 2301142.2 i/s oj: 7243770.3 i/s - 3.15x faster rapidjson: 3322673.0 i/s - 1.44x faster ``` After: ``` == Encoding small nested array (121 bytes) ruby 3.4.0preview2 (2024-10-07 master32c733f57b
) +YJIT +PRISM [arm64-darwin23] Warming up -------------------------------------- json 168.087k i/100ms oj 208.872k i/100ms rapidjson 149.909k i/100ms Calculating ------------------------------------- json 1.761M (± 1.1%) i/s (567.90 ns/i) - 8.909M in 5.059794s oj 2.144M (± 0.9%) i/s (466.37 ns/i) - 10.861M in 5.065903s rapidjson 1.692M (± 1.7%) i/s (591.04 ns/i) - 8.545M in 5.051808s Comparison: json: 1760868.2 i/s oj: 2144205.9 i/s - 1.22x faster rapidjson: 1691941.1 i/s - 1.04x slower == Encoding small hash (65 bytes) ruby 3.4.0preview2 (2024-10-07 master32c733f57b
) +YJIT +PRISM [arm64-darwin23] Warming up -------------------------------------- json 242.957k i/100ms oj 675.217k i/100ms rapidjson 355.040k i/100ms Calculating ------------------------------------- json 2.569M (± 1.5%) i/s (389.22 ns/i) - 12.877M in 5.013095s oj 7.128M (± 2.3%) i/s (140.30 ns/i) - 35.787M in 5.023594s rapidjson 3.656M (± 3.1%) i/s (273.50 ns/i) - 18.462M in 5.054558s Comparison: json: 2569217.5 i/s oj: 7127705.6 i/s - 2.77x faster rapidjson: 3656285.0 i/s - 1.42x faster ```
135 lines
4.1 KiB
Ruby
135 lines
4.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module JSON
|
|
module Ext
|
|
module Generator
|
|
class State
|
|
# call-seq: new(opts = {})
|
|
#
|
|
# Instantiates a new State object, configured by _opts_.
|
|
#
|
|
# _opts_ can have the following keys:
|
|
#
|
|
# * *indent*: a string used to indent levels (default: ''),
|
|
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
# generated, otherwise an exception is thrown, if these values are
|
|
# encountered. This options defaults to false.
|
|
# * *ascii_only*: true if only ASCII characters should be generated. This
|
|
# option defaults to false.
|
|
# * *buffer_initial_length*: sets the initial length of the generator's
|
|
# internal buffer.
|
|
def initialize(opts = nil)
|
|
if opts && !opts.empty?
|
|
configure(opts)
|
|
end
|
|
end
|
|
|
|
# call-seq: configure(opts)
|
|
#
|
|
# Configure this State instance with the Hash _opts_, and return
|
|
# itself.
|
|
def configure(opts)
|
|
unless opts.is_a?(Hash)
|
|
if opts.respond_to?(:to_hash)
|
|
opts = opts.to_hash
|
|
elsif opts.respond_to?(:to_h)
|
|
opts = opts.to_h
|
|
else
|
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
end
|
|
end
|
|
|
|
opts.each do |key, value|
|
|
case key
|
|
when :indent
|
|
self.indent = value
|
|
when :space
|
|
self.space = value
|
|
when :space_before
|
|
self.space_before = value
|
|
when :array_nl
|
|
self.array_nl = value
|
|
when :object_nl
|
|
self.object_nl = value
|
|
when :max_nesting
|
|
self.max_nesting = value || 0
|
|
when :depth
|
|
self.depth = value
|
|
when :buffer_initial_length
|
|
self.buffer_initial_length = value
|
|
when :allow_nan
|
|
self.allow_nan = value
|
|
when :ascii_only
|
|
self.ascii_only = value
|
|
when :script_safe, :escape_slash
|
|
self.script_safe = value
|
|
when :strict
|
|
self.strict = value
|
|
end
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
alias_method :merge, :configure
|
|
|
|
# call-seq: to_h
|
|
#
|
|
# Returns the configuration instance variables as a hash, that can be
|
|
# passed to the configure method.
|
|
def to_h
|
|
result = {
|
|
indent: indent,
|
|
space: space,
|
|
space_before: space_before,
|
|
object_nl: object_nl,
|
|
array_nl: array_nl,
|
|
allow_nan: allow_nan?,
|
|
ascii_only: ascii_only?,
|
|
max_nesting: max_nesting,
|
|
script_safe: script_safe?,
|
|
strict: strict?,
|
|
depth: depth,
|
|
buffer_initial_length: buffer_initial_length,
|
|
}
|
|
|
|
instance_variables.each do |iv|
|
|
iv = iv.to_s[1..-1]
|
|
result[iv.to_sym] = self[iv]
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
alias_method :to_hash, :to_h
|
|
|
|
# call-seq: [](name)
|
|
#
|
|
# Returns the value returned by method +name+.
|
|
def [](name)
|
|
if respond_to?(name)
|
|
__send__(name)
|
|
else
|
|
instance_variable_get("@#{name}") if
|
|
instance_variables.include?("@#{name}".to_sym) # avoid warning
|
|
end
|
|
end
|
|
|
|
# call-seq: []=(name, value)
|
|
#
|
|
# Sets the attribute name to value.
|
|
def []=(name, value)
|
|
if respond_to?(name_writer = "#{name}=")
|
|
__send__ name_writer, value
|
|
else
|
|
instance_variable_set "@#{name}", value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|