Reduce allocations in dependency construction
By always passing around a single, unnested array rather than splatting and then defensively flattening and compacting things, we can avoid allocating a bunch of unnecessary arrays. This gives a performance boost of roughly 4% when enumerating 2500 formulae, and has the side effect of cleaning up the dependency API.
This commit is contained in:
parent
894a6c9776
commit
b322020338
@ -6,9 +6,9 @@ class Dependency
|
|||||||
|
|
||||||
attr_reader :name, :tags
|
attr_reader :name, :tags
|
||||||
|
|
||||||
def initialize(name, *tags)
|
def initialize(name, tags=[])
|
||||||
@name = name
|
@name = name
|
||||||
@tags = tags.flatten.compact
|
@tags = tags
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
|||||||
@ -38,87 +38,89 @@ class DependencyCollector
|
|||||||
end
|
end
|
||||||
|
|
||||||
def build(spec)
|
def build(spec)
|
||||||
spec, tag = case spec
|
spec, tags = case spec
|
||||||
when Hash then spec.shift
|
when Hash then spec.shift
|
||||||
else spec
|
else spec
|
||||||
end
|
end
|
||||||
|
|
||||||
parse_spec(spec, tag)
|
parse_spec(spec, Array(tags))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def parse_spec spec, tag
|
def parse_spec(spec, tags)
|
||||||
case spec
|
case spec
|
||||||
when String
|
when String
|
||||||
parse_string_spec(spec, tag)
|
parse_string_spec(spec, tags)
|
||||||
when Symbol
|
when Symbol
|
||||||
parse_symbol_spec(spec, tag)
|
parse_symbol_spec(spec, tags)
|
||||||
when Requirement, Dependency
|
when Requirement, Dependency
|
||||||
spec
|
spec
|
||||||
when Class
|
when Class
|
||||||
parse_class_spec(spec, tag)
|
parse_class_spec(spec, tags)
|
||||||
else
|
else
|
||||||
raise TypeError, "Unsupported type #{spec.class} for #{spec}"
|
raise TypeError, "Unsupported type #{spec.class} for #{spec}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_string_spec(spec, tag)
|
def parse_string_spec(spec, tags)
|
||||||
if tag && LANGUAGE_MODULES.include?(tag)
|
if tags.empty?
|
||||||
|
Dependency.new(spec, tags)
|
||||||
|
elsif (tag = tags.first) && LANGUAGE_MODULES.include?(tag)
|
||||||
LanguageModuleDependency.new(tag, spec)
|
LanguageModuleDependency.new(tag, spec)
|
||||||
else
|
else
|
||||||
Dependency.new(spec, tag)
|
Dependency.new(spec, tags)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_symbol_spec spec, tag
|
def parse_symbol_spec(spec, tags)
|
||||||
case spec
|
case spec
|
||||||
when :autoconf, :automake, :bsdmake, :libtool, :libltdl
|
when :autoconf, :automake, :bsdmake, :libtool, :libltdl
|
||||||
# Xcode no longer provides autotools or some other build tools
|
# Xcode no longer provides autotools or some other build tools
|
||||||
autotools_dep(spec, tag)
|
autotools_dep(spec, tags)
|
||||||
when :x11 then X11Dependency.new(spec.to_s, tag)
|
when :x11 then X11Dependency.new(spec.to_s, tags)
|
||||||
when *X11Dependency::Proxy::PACKAGES
|
when *X11Dependency::Proxy::PACKAGES
|
||||||
x11_dep(spec, tag)
|
x11_dep(spec, tags)
|
||||||
when :cairo, :pixman
|
when :cairo, :pixman
|
||||||
# We no longer use X11 psuedo-deps for cairo or pixman,
|
# We no longer use X11 psuedo-deps for cairo or pixman,
|
||||||
# so just return a standard formula dependency.
|
# so just return a standard formula dependency.
|
||||||
Dependency.new(spec.to_s, tag)
|
Dependency.new(spec.to_s, tags)
|
||||||
when :xcode then XcodeDependency.new(tag)
|
when :xcode then XcodeDependency.new(tags)
|
||||||
when :mysql then MysqlDependency.new(tag)
|
when :mysql then MysqlDependency.new(tags)
|
||||||
when :postgresql then PostgresqlDependency.new(tag)
|
when :postgresql then PostgresqlDependency.new(tags)
|
||||||
when :tex then TeXDependency.new(tag)
|
when :tex then TeXDependency.new(tags)
|
||||||
when :clt then CLTDependency.new(tag)
|
when :clt then CLTDependency.new(tags)
|
||||||
when :arch then ArchRequirement.new(tag)
|
when :arch then ArchRequirement.new(tags)
|
||||||
when :hg then MercurialDependency.new(tag)
|
when :hg then MercurialDependency.new(tags)
|
||||||
else
|
else
|
||||||
raise "Unsupported special dependency #{spec}"
|
raise "Unsupported special dependency #{spec}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_class_spec(spec, tag)
|
def parse_class_spec(spec, tags)
|
||||||
if spec < Requirement
|
if spec < Requirement
|
||||||
spec.new(tag)
|
spec.new(tags)
|
||||||
else
|
else
|
||||||
raise TypeError, "#{spec} is not a Requirement subclass"
|
raise TypeError, "#{spec} is not a Requirement subclass"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def x11_dep(spec, tag)
|
def x11_dep(spec, tags)
|
||||||
if MacOS.version >= :mountain_lion
|
if MacOS.version >= :mountain_lion
|
||||||
Dependency.new(spec.to_s, tag)
|
Dependency.new(spec.to_s, tags)
|
||||||
else
|
else
|
||||||
X11Dependency::Proxy.for(spec.to_s, tag)
|
X11Dependency::Proxy.for(spec.to_s, tags)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def autotools_dep(spec, tag)
|
def autotools_dep(spec, tags)
|
||||||
case spec
|
|
||||||
when :libltdl then spec, tag = :libtool, Array(tag)
|
|
||||||
else tag = Array(tag) << :build
|
|
||||||
end
|
|
||||||
|
|
||||||
unless MacOS::Xcode.provides_autotools?
|
unless MacOS::Xcode.provides_autotools?
|
||||||
Dependency.new(spec.to_s, tag)
|
case spec
|
||||||
|
when :libltdl then spec = :libtool
|
||||||
|
else tags << :build
|
||||||
|
end
|
||||||
|
|
||||||
|
Dependency.new(spec.to_s, tags)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -10,8 +10,8 @@ class Requirement
|
|||||||
|
|
||||||
attr_reader :tags, :name
|
attr_reader :tags, :name
|
||||||
|
|
||||||
def initialize(*tags)
|
def initialize(tags=[])
|
||||||
@tags = tags.flatten.compact
|
@tags = tags
|
||||||
@tags << :build if self.class.build
|
@tags << :build if self.class.build
|
||||||
@name ||= infer_name
|
@name ||= infer_name
|
||||||
end
|
end
|
||||||
|
|||||||
@ -7,7 +7,7 @@ class LanguageModuleDependency < Requirement
|
|||||||
@language = language
|
@language = language
|
||||||
@module_name = module_name
|
@module_name = module_name
|
||||||
@import_name = import_name
|
@import_name = import_name
|
||||||
super
|
super([language, module_name, import_name])
|
||||||
end
|
end
|
||||||
|
|
||||||
satisfy { quiet_system(*the_test) }
|
satisfy { quiet_system(*the_test) }
|
||||||
|
|||||||
@ -9,8 +9,7 @@ class X11Dependency < Requirement
|
|||||||
|
|
||||||
env { ENV.x11 }
|
env { ENV.x11 }
|
||||||
|
|
||||||
def initialize(name="x11", *tags)
|
def initialize(name="x11", tags=[])
|
||||||
tags.flatten!
|
|
||||||
@name = name
|
@name = name
|
||||||
@min_version = tags.shift if /(\d\.)+\d/ === tags.first
|
@min_version = tags.shift if /(\d\.)+\d/ === tags.first
|
||||||
super(tags)
|
super(tags)
|
||||||
@ -66,19 +65,19 @@ class X11Dependency < Requirement
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def for(name, *tags)
|
def for(name, tags=[])
|
||||||
constant = name.capitalize
|
constant = name.capitalize
|
||||||
|
|
||||||
if defines_const?(constant)
|
if defines_const?(constant)
|
||||||
klass = const_get(constant)
|
klass = const_get(constant)
|
||||||
else
|
else
|
||||||
klass = Class.new(self) do
|
klass = Class.new(self) do
|
||||||
def initialize(name, *tags) super end
|
def initialize(name, tags) super end
|
||||||
end
|
end
|
||||||
|
|
||||||
const_set(constant, klass)
|
const_set(constant, klass)
|
||||||
end
|
end
|
||||||
klass.new(name, *tags)
|
klass.new(name, tags)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -17,25 +17,25 @@ class ComparableSetTests < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_comparison_prefers_larger
|
def test_comparison_prefers_larger
|
||||||
@set << X11Dependency.new
|
@set << X11Dependency.new
|
||||||
@set << X11Dependency.new('x11', '2.6')
|
@set << X11Dependency.new('x11', %w{2.6})
|
||||||
assert_equal 1, @set.count
|
assert_equal 1, @set.count
|
||||||
assert_equal [X11Dependency.new('x11', '2.6')], @set.to_a
|
assert_equal [X11Dependency.new('x11', %w{2.6})], @set.to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_comparison_does_not_merge_smaller
|
def test_comparison_does_not_merge_smaller
|
||||||
@set << X11Dependency.new('x11', '2.6')
|
@set << X11Dependency.new('x11', %w{2.6})
|
||||||
@set << X11Dependency.new
|
@set << X11Dependency.new
|
||||||
assert_equal 1, @set.count
|
assert_equal 1, @set.count
|
||||||
assert_equal [X11Dependency.new('x11', '2.6')], @set.to_a
|
assert_equal [X11Dependency.new('x11', %w{2.6})], @set.to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_merging_sets
|
def test_merging_sets
|
||||||
@set << X11Dependency.new
|
@set << X11Dependency.new
|
||||||
@set << Requirement.new
|
@set << Requirement.new
|
||||||
reqs = Set.new [X11Dependency.new('x11', '2.6'), Requirement.new]
|
reqs = Set.new [X11Dependency.new('x11', %w{2.6}), Requirement.new]
|
||||||
assert_same @set, @set.merge(reqs)
|
assert_same @set, @set.merge(reqs)
|
||||||
|
|
||||||
assert_equal 2, @set.count
|
assert_equal 2, @set.count
|
||||||
assert_equal X11Dependency.new('x11', '2.6'), @set.find {|r| r.is_a? X11Dependency}
|
assert_equal X11Dependency.new('x11', %w{2.6}), @set.find {|r| r.is_a? X11Dependency}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -20,7 +20,7 @@ end
|
|||||||
|
|
||||||
class DependencyTests < Test::Unit::TestCase
|
class DependencyTests < Test::Unit::TestCase
|
||||||
def test_accepts_single_tag
|
def test_accepts_single_tag
|
||||||
dep = Dependency.new("foo", "bar")
|
dep = Dependency.new("foo", %w{bar})
|
||||||
assert_equal %w{bar}, dep.tags
|
assert_equal %w{bar}, dep.tags
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class DependencyTests < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_preserves_symbol_tags
|
def test_preserves_symbol_tags
|
||||||
dep = Dependency.new("foo", :build)
|
dep = Dependency.new("foo", [:build])
|
||||||
assert_equal [:build], dep.tags
|
assert_equal [:build], dep.tags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class DependencyCollectorTests < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_dependency_tags
|
def test_dependency_tags
|
||||||
assert Dependency.new('foo', :build).build?
|
assert Dependency.new('foo', [:build]).build?
|
||||||
assert Dependency.new('foo', [:build, :optional]).optional?
|
assert Dependency.new('foo', [:build, :optional]).optional?
|
||||||
assert Dependency.new('foo', [:universal]).options.include? '--universal'
|
assert Dependency.new('foo', [:universal]).options.include? '--universal'
|
||||||
assert_empty Dependency.new('foo').tags
|
assert_empty Dependency.new('foo').tags
|
||||||
|
|||||||
@ -3,27 +3,23 @@ require 'requirement'
|
|||||||
|
|
||||||
class RequirementTests < Test::Unit::TestCase
|
class RequirementTests < Test::Unit::TestCase
|
||||||
def test_accepts_single_tag
|
def test_accepts_single_tag
|
||||||
dep = Requirement.new("bar")
|
dep = Requirement.new(%w{bar})
|
||||||
assert_equal %w{bar}, dep.tags
|
assert_equal %w{bar}, dep.tags
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_accepts_multiple_tags
|
def test_accepts_multiple_tags
|
||||||
dep = Requirement.new(%w{bar baz})
|
dep = Requirement.new(%w{bar baz})
|
||||||
assert_equal %w{bar baz}.sort, dep.tags.sort
|
assert_equal %w{bar baz}.sort, dep.tags.sort
|
||||||
dep = Requirement.new(*%w{bar baz})
|
|
||||||
assert_equal %w{bar baz}.sort, dep.tags.sort
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_preserves_symbol_tags
|
def test_preserves_symbol_tags
|
||||||
dep = Requirement.new(:build)
|
dep = Requirement.new([:build])
|
||||||
assert_equal [:build], dep.tags
|
assert_equal [:build], dep.tags
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_accepts_symbol_and_string_tags
|
def test_accepts_symbol_and_string_tags
|
||||||
dep = Requirement.new([:build, "bar"])
|
dep = Requirement.new([:build, "bar"])
|
||||||
assert_equal [:build, "bar"], dep.tags
|
assert_equal [:build, "bar"], dep.tags
|
||||||
dep = Requirement.new(:build, "bar")
|
|
||||||
assert_equal [:build, "bar"], dep.tags
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dsl_fatal
|
def test_dsl_fatal
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user