From f4c2ac4825f99ec4af529d65ae98abfaf034fb0f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 2 Mar 2017 04:08:23 +0000 Subject: deduplicate strings using String#-@ (uminus) in Ruby 2.5+ This is faster than relying on eval() for older Rubies. https://bugs.ruby-lang.org/issues/13077 Ruby 2.5 is targetted for release in December 2017. --- lib/dtas.rb | 13 +++++++++++++ lib/dtas/fadefx.rb | 2 +- lib/dtas/mlib.rb | 10 ++++++---- lib/dtas/partstats.rb | 3 +-- lib/dtas/player.rb | 2 +- lib/dtas/player/client_handler.rb | 5 +++-- lib/dtas/rg_state.rb | 2 +- lib/dtas/source/av_ff_common.rb | 8 ++++++-- lib/dtas/source/sox.rb | 7 ++----- 9 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lib/dtas.rb b/lib/dtas.rb index 1a1a882..ac416d7 100644 --- a/lib/dtas.rb +++ b/lib/dtas.rb @@ -24,6 +24,19 @@ module DTAS def self.null # :nodoc: @null ||= File.open('/dev/null', 'r+') end + + # String#-@ will deduplicate strings when Ruby 2.5 is released (Dec 2017) + # https://bugs.ruby-lang.org/issues/13077 + if RUBY_VERSION.to_f >= 2.5 + def self.dedupe_str(str) + -str + end + else + # Ruby 2.1 - 2.4, noop for older Rubies + def self.dedupe_str(str) + eval "#{str.inspect}.freeze" + end + end # :startdoc: end diff --git a/lib/dtas/fadefx.rb b/lib/dtas/fadefx.rb index aca6c68..1a00653 100644 --- a/lib/dtas/fadefx.rb +++ b/lib/dtas/fadefx.rb @@ -95,7 +95,7 @@ class DTAS::FadeFX # :nodoc: def parse!(str) return nil if str.empty? type = "t" - str.sub!(/\A([a-z])/, "") and type = $1.freeze + str.sub!(/\A([a-z])/, "") and type = DTAS.dedupe_str($1) F.new(type, parse_time(str)) end end diff --git a/lib/dtas/mlib.rb b/lib/dtas/mlib.rb index dbd46da..0945153 100644 --- a/lib/dtas/mlib.rb +++ b/lib/dtas/mlib.rb @@ -190,7 +190,9 @@ class DTAS::Mlib # :nodoc: tag_id = tag_map[x] and tag_map["#{x}number"] = tag_id end @tag_rmap = tag_map.invert.freeze - tag_map.merge!(Hash[*(tag_map.map { |k,v| [k.upcase.freeze, v] }.flatten!)]) + tag_map.merge!(Hash[*(tag_map.map { |k,v| + [DTAS.dedupe_str(k.upcase), v] + }.flatten!)]) @tag_map = tag_map.freeze end @@ -400,7 +402,7 @@ class DTAS::Mlib # :nodoc: return '/' if base == '' # root_node parent_id = node[:parent_id] base += '/' unless node[:tlen] >= 0 - ppath = cache[parent_id] and return "#{ppath}/#{base}" + ppath = cache[parent_id] and return DTAS.dedupe_str("#{ppath}/#{base}") parts = [] begin node = @db[:nodes][id: node[:parent_id]] @@ -408,9 +410,9 @@ class DTAS::Mlib # :nodoc: parts.unshift node[:name] end while true parts.unshift('') - cache[parent_id] = parts.join('/') + cache[parent_id] = DTAS.dedupe_str(parts.join('/')) parts << base - parts.join('/').freeze + DTAS.dedupe_str(parts.join('/')) end def emit_recurse(node, cache, cb) diff --git a/lib/dtas/partstats.rb b/lib/dtas/partstats.rb index f9f2116..1037c87 100644 --- a/lib/dtas/partstats.rb +++ b/lib/dtas/partstats.rb @@ -173,8 +173,7 @@ becomes: else next end - key = $1 - key.freeze + key = DTAS.dedupe_str($1) key_idx = @key_idx[key] parts = line.split(/\s+/) nshift.times { parts.shift } # remove stuff we don't need diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb index 45a1da8..37f2c96 100644 --- a/lib/dtas/player.rb +++ b/lib/dtas/player.rb @@ -168,7 +168,7 @@ class DTAS::Player # :nodoc: if sinks = hash["sinks"] sinks.each do |sink_hsh| - sink_hsh['name'].freeze + sink_hsh['name'] = DTAS.dedupe_str(sink_hsh['name']) sink = DTAS::Sink.load(sink_hsh) sink.env = to_omap(sink.env) @sinks[sink.name] = sink diff --git a/lib/dtas/player/client_handler.rb b/lib/dtas/player/client_handler.rb index b17e90b..1e4ac96 100644 --- a/lib/dtas/player/client_handler.rb +++ b/lib/dtas/player/client_handler.rb @@ -3,6 +3,7 @@ # frozen_string_literal: true require_relative '../xs' require_relative '../parse_time' +require_relative '../../dtas' # client protocol handling for -player module DTAS::Player::ClientHandler # :nodoc: @@ -134,7 +135,7 @@ module DTAS::Player::ClientHandler # :nodoc: # or variable names. sink.valid_name?(name) or return io.emit("ERR sink name invalid") - sink.name = name.freeze + sink.name = DTAS.dedupe_str(name) active_before = sink.active before = __sink_snapshot(sink) @@ -143,7 +144,7 @@ module DTAS::Player::ClientHandler # :nodoc: k, v = kv.split('=', 2) case k when %r{\Aenv\.([^=]+)\z} - sink.env[$1] = v + sink.env[DTAS.dedupe_str($1)] = v when %r{\Aenv#([^=]+)\z} v == nil or return io.emit("ERR unset env has no value") sink.env.delete($1) diff --git a/lib/dtas/rg_state.rb b/lib/dtas/rg_state.rb index 7af67e1..6b2c718 100644 --- a/lib/dtas/rg_state.rb +++ b/lib/dtas/rg_state.rb @@ -72,7 +72,7 @@ class DTAS::RGState # :nodoc: when 1 then return 'gain 192' else val.abs <= 0.00000001 and return - sprintf('gain %0.8f', val).freeze + DTAS.dedupe_str(sprintf('gain %0.8f', val)) end end diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb index d89ea17..ae654ba 100644 --- a/lib/dtas/source/av_ff_common.rb +++ b/lib/dtas/source/av_ff_common.rb @@ -109,13 +109,17 @@ module DTAS::Source::AvFfCommon # :nodoc: f = $1.dup f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f # TODO: multi-line/multi-value/repeated tags - f.gsub!(/^TAG:([^=]+)=(.*)$/ni) { |_| @comments[$1.upcase.freeze] = $2 } + f.gsub!(/^TAG:([^=]+)=(.*)$/ni) { |_| + @comments[DTAS.dedupe_str($1.upcase)] = DTAS.dedupe_str($2) + } end # new avprobe s.scan(%r{^\[format\.tags\]\n(.*?)\n\n}m) do |_| f = $1.dup - f.gsub!(/^([^=]+)=(.*)$/ni) { |_| @comments[$1.upcase.freeze] = $2 } + f.gsub!(/^([^=]+)=(.*)$/ni) { |_| + @comments[DTAS.dedupe_str($1.upcase)] = DTAS.dedupe_str($2) + } end s.scan(%r{^\[format\]\n(.*?)\n\n}m) do |_| f = $1.dup diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb index 7f55c5d..f702b41 100644 --- a/lib/dtas/source/sox.rb +++ b/lib/dtas/source/sox.rb @@ -52,19 +52,16 @@ class DTAS::Source::Sox # :nodoc: if out =~ /\nComments\s*:[ \t]*\n?(.*)\z/mn comments = dst['comments'] = {} - # we use eval "#{str.inspect}".freeze - # take advantage of the VM-wide dedupe in MRI (rb_fstring): key = nil $1.split(/\n/n).each do |line| if line.sub!(/^([^=]+)=/ni, '') - key = $1.upcase - key = eval "#{key.inspect}.freeze" + key = DTAS.dedupe_str($1.upcase) end (comments[key] ||= ''.b) << "#{line}\n" unless line.empty? end comments.each do |k,v| v.chomp! - comments[k] = eval "#{v.inspect}.freeze" + comments[k] = DTAS.dedupe_str(v) end end dst -- cgit v1.2.3-24-ge0c7