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
|
||||
|
||||
def initialize(name, *tags)
|
||||
def initialize(name, tags=[])
|
||||
@name = name
|
||||
@tags = tags.flatten.compact
|
||||
@tags = tags
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
||||
@ -38,87 +38,89 @@ class DependencyCollector
|
||||
end
|
||||
|
||||
def build(spec)
|
||||
spec, tag = case spec
|
||||
spec, tags = case spec
|
||||
when Hash then spec.shift
|
||||
else spec
|
||||
end
|
||||
|
||||
parse_spec(spec, tag)
|
||||
parse_spec(spec, Array(tags))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_spec spec, tag
|
||||
def parse_spec(spec, tags)
|
||||
case spec
|
||||
when String
|
||||
parse_string_spec(spec, tag)
|
||||
parse_string_spec(spec, tags)
|
||||
when Symbol
|
||||
parse_symbol_spec(spec, tag)
|
||||
parse_symbol_spec(spec, tags)
|
||||
when Requirement, Dependency
|
||||
spec
|
||||
when Class
|
||||
parse_class_spec(spec, tag)
|
||||
parse_class_spec(spec, tags)
|
||||
else
|
||||
raise TypeError, "Unsupported type #{spec.class} for #{spec}"
|
||||
end
|
||||
end
|
||||
|
||||
def parse_string_spec(spec, tag)
|
||||
if tag && LANGUAGE_MODULES.include?(tag)
|
||||
def parse_string_spec(spec, tags)
|
||||
if tags.empty?
|
||||
Dependency.new(spec, tags)
|
||||
elsif (tag = tags.first) && LANGUAGE_MODULES.include?(tag)
|
||||
LanguageModuleDependency.new(tag, spec)
|
||||
else
|
||||
Dependency.new(spec, tag)
|
||||
Dependency.new(spec, tags)
|
||||
end
|
||||
end
|
||||
|
||||
def parse_symbol_spec spec, tag
|
||||
def parse_symbol_spec(spec, tags)
|
||||
case spec
|
||||
when :autoconf, :automake, :bsdmake, :libtool, :libltdl
|
||||
# Xcode no longer provides autotools or some other build tools
|
||||
autotools_dep(spec, tag)
|
||||
when :x11 then X11Dependency.new(spec.to_s, tag)
|
||||
autotools_dep(spec, tags)
|
||||
when :x11 then X11Dependency.new(spec.to_s, tags)
|
||||
when *X11Dependency::Proxy::PACKAGES
|
||||
x11_dep(spec, tag)
|
||||
x11_dep(spec, tags)
|
||||
when :cairo, :pixman
|
||||
# We no longer use X11 psuedo-deps for cairo or pixman,
|
||||
# so just return a standard formula dependency.
|
||||
Dependency.new(spec.to_s, tag)
|
||||
when :xcode then XcodeDependency.new(tag)
|
||||
when :mysql then MysqlDependency.new(tag)
|
||||
when :postgresql then PostgresqlDependency.new(tag)
|
||||
when :tex then TeXDependency.new(tag)
|
||||
when :clt then CLTDependency.new(tag)
|
||||
when :arch then ArchRequirement.new(tag)
|
||||
when :hg then MercurialDependency.new(tag)
|
||||
Dependency.new(spec.to_s, tags)
|
||||
when :xcode then XcodeDependency.new(tags)
|
||||
when :mysql then MysqlDependency.new(tags)
|
||||
when :postgresql then PostgresqlDependency.new(tags)
|
||||
when :tex then TeXDependency.new(tags)
|
||||
when :clt then CLTDependency.new(tags)
|
||||
when :arch then ArchRequirement.new(tags)
|
||||
when :hg then MercurialDependency.new(tags)
|
||||
else
|
||||
raise "Unsupported special dependency #{spec}"
|
||||
end
|
||||
end
|
||||
|
||||
def parse_class_spec(spec, tag)
|
||||
def parse_class_spec(spec, tags)
|
||||
if spec < Requirement
|
||||
spec.new(tag)
|
||||
spec.new(tags)
|
||||
else
|
||||
raise TypeError, "#{spec} is not a Requirement subclass"
|
||||
end
|
||||
end
|
||||
|
||||
def x11_dep(spec, tag)
|
||||
def x11_dep(spec, tags)
|
||||
if MacOS.version >= :mountain_lion
|
||||
Dependency.new(spec.to_s, tag)
|
||||
Dependency.new(spec.to_s, tags)
|
||||
else
|
||||
X11Dependency::Proxy.for(spec.to_s, tag)
|
||||
X11Dependency::Proxy.for(spec.to_s, tags)
|
||||
end
|
||||
end
|
||||
|
||||
def autotools_dep(spec, tag)
|
||||
case spec
|
||||
when :libltdl then spec, tag = :libtool, Array(tag)
|
||||
else tag = Array(tag) << :build
|
||||
end
|
||||
|
||||
def autotools_dep(spec, tags)
|
||||
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
|
||||
|
||||
@ -10,8 +10,8 @@ class Requirement
|
||||
|
||||
attr_reader :tags, :name
|
||||
|
||||
def initialize(*tags)
|
||||
@tags = tags.flatten.compact
|
||||
def initialize(tags=[])
|
||||
@tags = tags
|
||||
@tags << :build if self.class.build
|
||||
@name ||= infer_name
|
||||
end
|
||||
|
||||
@ -7,7 +7,7 @@ class LanguageModuleDependency < Requirement
|
||||
@language = language
|
||||
@module_name = module_name
|
||||
@import_name = import_name
|
||||
super
|
||||
super([language, module_name, import_name])
|
||||
end
|
||||
|
||||
satisfy { quiet_system(*the_test) }
|
||||
|
||||
@ -9,8 +9,7 @@ class X11Dependency < Requirement
|
||||
|
||||
env { ENV.x11 }
|
||||
|
||||
def initialize(name="x11", *tags)
|
||||
tags.flatten!
|
||||
def initialize(name="x11", tags=[])
|
||||
@name = name
|
||||
@min_version = tags.shift if /(\d\.)+\d/ === tags.first
|
||||
super(tags)
|
||||
@ -66,19 +65,19 @@ class X11Dependency < Requirement
|
||||
end
|
||||
end
|
||||
|
||||
def for(name, *tags)
|
||||
def for(name, tags=[])
|
||||
constant = name.capitalize
|
||||
|
||||
if defines_const?(constant)
|
||||
klass = const_get(constant)
|
||||
else
|
||||
klass = Class.new(self) do
|
||||
def initialize(name, *tags) super end
|
||||
def initialize(name, tags) super end
|
||||
end
|
||||
|
||||
const_set(constant, klass)
|
||||
end
|
||||
klass.new(name, *tags)
|
||||
klass.new(name, tags)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -17,25 +17,25 @@ class ComparableSetTests < Test::Unit::TestCase
|
||||
|
||||
def test_comparison_prefers_larger
|
||||
@set << X11Dependency.new
|
||||
@set << X11Dependency.new('x11', '2.6')
|
||||
@set << X11Dependency.new('x11', %w{2.6})
|
||||
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
|
||||
|
||||
def test_comparison_does_not_merge_smaller
|
||||
@set << X11Dependency.new('x11', '2.6')
|
||||
@set << X11Dependency.new('x11', %w{2.6})
|
||||
@set << X11Dependency.new
|
||||
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
|
||||
|
||||
def test_merging_sets
|
||||
@set << X11Dependency.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_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
|
||||
|
||||
@ -20,7 +20,7 @@ end
|
||||
|
||||
class DependencyTests < Test::Unit::TestCase
|
||||
def test_accepts_single_tag
|
||||
dep = Dependency.new("foo", "bar")
|
||||
dep = Dependency.new("foo", %w{bar})
|
||||
assert_equal %w{bar}, dep.tags
|
||||
end
|
||||
|
||||
@ -30,7 +30,7 @@ class DependencyTests < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_preserves_symbol_tags
|
||||
dep = Dependency.new("foo", :build)
|
||||
dep = Dependency.new("foo", [:build])
|
||||
assert_equal [:build], dep.tags
|
||||
end
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ class DependencyCollectorTests < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
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', [:universal]).options.include? '--universal'
|
||||
assert_empty Dependency.new('foo').tags
|
||||
|
||||
@ -3,27 +3,23 @@ require 'requirement'
|
||||
|
||||
class RequirementTests < Test::Unit::TestCase
|
||||
def test_accepts_single_tag
|
||||
dep = Requirement.new("bar")
|
||||
dep = Requirement.new(%w{bar})
|
||||
assert_equal %w{bar}, dep.tags
|
||||
end
|
||||
|
||||
def test_accepts_multiple_tags
|
||||
dep = Requirement.new(%w{bar baz})
|
||||
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
|
||||
|
||||
def test_preserves_symbol_tags
|
||||
dep = Requirement.new(:build)
|
||||
dep = Requirement.new([:build])
|
||||
assert_equal [:build], dep.tags
|
||||
end
|
||||
|
||||
def test_accepts_symbol_and_string_tags
|
||||
dep = Requirement.new([:build, "bar"])
|
||||
assert_equal [:build, "bar"], dep.tags
|
||||
dep = Requirement.new(:build, "bar")
|
||||
assert_equal [:build, "bar"], dep.tags
|
||||
end
|
||||
|
||||
def test_dsl_fatal
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user