From 3733cb611464b81b1d9f08a3c4e47b485876a204 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 4 Oct 2019 15:01:32 -0400 Subject: [PATCH] Backport 2.x VarSet performance improvements to 1.x branch. --- lib/rscons/environment.rb | 28 ++++++++++++--- lib/rscons/varset.rb | 71 +++++++++++++++++++++++++++----------- spec/rscons/varset_spec.rb | 2 +- 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/lib/rscons/environment.rb b/lib/rscons/environment.rb index 62cd121..c1a3471 100644 --- a/lib/rscons/environment.rb +++ b/lib/rscons/environment.rb @@ -280,6 +280,24 @@ module Rscons @varset.send(:[], *args) end + # Access the value of a construction variable. + # + # @since 1.18.0 + # + # This method is similar to #[] but does not make a copy-on-access copy of + # the variable accessed. This means that the returned value is NOT safe to + # be modified by the caller. Thus the caller must guarantee that it does + # not modify the returned value. + # + # @param key [String, Symbol] + # The construction variable name. + # + # @return [Object] + # The construction variable's value. + def get_var(key) + @varset.get_var(key) + end + # Set a construction variable's value. # # @see VarSet#[]= @@ -782,7 +800,7 @@ module Rscons append["LDFLAGS", ["-arch", val]] end skip = true - elsif word =~ /^#{self["CPPDEFPREFIX"]}(.*)$/ + elsif word =~ /^#{get_var("CPPDEFPREFIX")}(.*)$/ handle["CPPDEFINES", $1] elsif word == "-include" if val = words[i + 1] @@ -795,11 +813,11 @@ module Rscons append["LDFLAGS", ["-isysroot", val]] end skip = true - elsif word =~ /^#{self["INCPREFIX"]}(.*)$/ + elsif word =~ /^#{get_var("INCPREFIX")}(.*)$/ handle["CPPPATH", $1] - elsif word =~ /^#{self["LIBLINKPREFIX"]}(.*)$/ + elsif word =~ /^#{get_var("LIBLINKPREFIX")}(.*)$/ handle["LIBS", $1] - elsif word =~ /^#{self["LIBDIRPREFIX"]}(.*)$/ + elsif word =~ /^#{get_var("LIBDIRPREFIX")}(.*)$/ handle["LIBPATH", $1] elsif word == "-mno-cygwin" append["CCFLAGS", [word]] @@ -848,7 +866,7 @@ module Rscons # @return [void] def merge_flags(flags) flags.each_pair do |key, val| - if self[key].is_a?(Array) and val.is_a?(Array) + if self.get_var(key).is_a?(Array) and val.is_a?(Array) self[key] += val else self[key] = val diff --git a/lib/rscons/varset.rb b/lib/rscons/varset.rb index 267a8a5..f6b6161 100644 --- a/lib/rscons/varset.rb +++ b/lib/rscons/varset.rb @@ -11,11 +11,13 @@ module Rscons append(vars) end - # Access the value of variable. + # Access the value of a variable. # - # @param key [String, Symbol] The variable name. + # @param key [String, Symbol] + # The variable name. # - # @return [Object] The variable's value. + # @return [Object] + # The variable's value. def [](key) if @my_vars.include?(key) @my_vars[key] @@ -30,11 +32,38 @@ module Rscons end end + # Access the value of a variable. + # + # This method is similar to #[] but does not make a copy-on-access copy of + # the variable accessed. This means that the returned value is NOT safe to + # be modified by the caller. Thus the caller must guarantee that it does + # not modify the returned value. + # + # @param key [String, Symbol] + # The variable name. + # + # @return [Object] + # The variable's value. + def get_var(key) + if @my_vars.include?(key) + @my_vars[key] + else + @coa_vars.each do |coa_vars| + if coa_vars.include?(key) + return coa_vars[key] + end + end + nil + end + end + # Assign a value to a variable. # - # @param key [String, Symbol] The variable name. + # @param key [String, Symbol] + # The variable name. # - # @param val [Object] The value to set. + # @param val [Object] + # The value to set. def []=(key, val) @my_vars[key] = val end @@ -95,29 +124,27 @@ module Rscons # Expanded value with "$!{var}" variable references replaced. def expand_varref(varref, lambda_args) case varref - when Symbol, true, false, nil - varref when String if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/ prefix, varname, suffix = $1, $2, $3 prefix = expand_varref(prefix, lambda_args) unless prefix.empty? - varval = expand_varref(self[varname], lambda_args) + varval = expand_varref(get_var(varname), lambda_args) # suffix needs no expansion since the regex matches the last occurence case varval - when Symbol, true, false, nil, String - if prefix.is_a?(Array) - prefix.map {|p| "#{p}#{varval}#{suffix}"} - else - "#{prefix}#{varval}#{suffix}" - end when Array if prefix.is_a?(Array) varval.map {|vv| prefix.map {|p| "#{p}#{vv}#{suffix}"}}.flatten else varval.map {|vv| "#{prefix}#{vv}#{suffix}"} end + when String, Symbol, true, false, nil + if prefix.is_a?(Array) + prefix.map {|p| "#{p}#{varval}#{suffix}"} + else + "#{prefix}#{varval}#{suffix}" + end else - raise "Unknown construction variable type: #{varval.class} (from #{varname.inspect} => #{self[varname].inspect})" + raise "Unknown construction variable type: #{varval.class} (from #{varname.inspect} => #{get_var(varname).inspect})" end else varref @@ -126,6 +153,8 @@ module Rscons varref.map do |ent| expand_varref(ent, lambda_args) end.flatten + when Symbol, true, false, nil + varref when Proc expand_varref(varref[*lambda_args], lambda_args) else @@ -194,16 +223,16 @@ module Rscons # # @return [Object] Deep copied value. def deep_dup(obj) - obj_class = obj.class - if obj_class == Hash + case obj + when String + obj.dup + when Array + obj.map { |v| deep_dup(v) } + when Hash obj.reduce({}) do |result, (k, v)| result[k] = deep_dup(v) result end - elsif obj_class == Array - obj.map { |v| deep_dup(v) } - elsif obj_class == String - obj.dup else obj end diff --git a/spec/rscons/varset_spec.rb b/spec/rscons/varset_spec.rb index ba920ef..14ffc5d 100644 --- a/spec/rscons/varset_spec.rb +++ b/spec/rscons/varset_spec.rb @@ -169,7 +169,7 @@ module Rscons expect { v.expand_varref({a: :b}, :lambda_args) }.to raise_error /Unknown construction variable type: Hash/ end it "raises an error when an expanded variable is an unexpected type" do - expect(v).to receive(:[]).at_least(1).times.with("bad").and_return("bad_val") + expect(v).to receive(:get_var).at_least(1).times.with("bad").and_return("bad_val") expect(v).to receive(:expand_varref).with("bad_val", :lambda_args).and_return({a: :b}) expect(v).to receive(:expand_varref).and_call_original expect { v.expand_varref("${bad}", :lambda_args) }.to raise_error /Unknown construction variable type: Hash/