Skip to content

Commit 9eeb28e

Browse files
martinemdedeivid-rodriguez
authored andcommitted
Merge pull request #6962 from rubygems/segiddins/avoid-allocating-empty-hashes-in-index
Avoid allocating empty hashes in Index (cherry picked from commit bf1c85d)
1 parent b909f7a commit 9eeb28e

File tree

1 file changed

+26
-20
lines changed

1 file changed

+26
-20
lines changed

bundler/lib/bundler/index.rb

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ def self.build
1919
def initialize
2020
@sources = []
2121
@cache = {}
22-
@specs = Hash.new {|h, k| h[k] = {} }
22+
@specs = {}
2323
@duplicates = {}
2424
end
2525

2626
def initialize_copy(o)
2727
@sources = o.sources.dup
2828
@cache = {}
29-
@specs = Hash.new {|h, k| h[k] = {} }
29+
@specs = {}
3030
@duplicates = {}
3131

3232
o.specs.each do |name, hash|
@@ -46,14 +46,11 @@ def empty?
4646
true
4747
end
4848

49-
def search_all(name)
50-
all_matches = specs_by_name(name) # always returns a new Array
51-
dupes = @duplicates[name]
52-
all_matches.concat(dupes) if dupes
53-
@sources.each do |source|
54-
all_matches.concat(source.search_all(name))
55-
end
56-
all_matches
49+
def search_all(name, &blk)
50+
return enum_for(:search_all, name) unless blk
51+
specs_by_name(name).each(&blk)
52+
@duplicates[name]&.each(&blk)
53+
@sources.each {|source| source.search_all(name, &blk) }
5754
end
5855

5956
# Search this index's specs, and any source indexes that this index knows
@@ -63,11 +60,14 @@ def search(query)
6360
return results unless @sources.any?
6461

6562
@sources.each do |source|
66-
results.concat(source.search(query))
63+
results = safe_concat(results, source.search(query))
6764
end
68-
results.uniq(&:full_name)
65+
results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH
66+
results
6967
end
7068

69+
alias_method :[], :search
70+
7171
def local_search(query)
7272
case query
7373
when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
@@ -78,11 +78,8 @@ def local_search(query)
7878
end
7979
end
8080

81-
alias_method :[], :search
82-
8381
def add(spec)
84-
@specs[spec.name][spec.full_name] = spec
85-
spec
82+
(@specs[spec.name] ||= {}).store(spec.full_name, spec)
8683
end
8784
alias_method :<<, :add
8885

@@ -170,16 +167,25 @@ def add_source(index)
170167

171168
private
172169

170+
def safe_concat(a, b)
171+
return a if b.empty?
172+
return b if a.empty?
173+
a.concat(b)
174+
end
175+
173176
def add_duplicate(spec)
174177
(@duplicates[spec.name] ||= []) << spec
175178
end
176179

177180
def specs_by_name_and_version(name, version)
178-
specs_by_name(name).select {|spec| spec.version == version }
181+
results = @specs[name]&.values
182+
return EMPTY_SEARCH unless results
183+
results.select! {|spec| spec.version == version }
184+
results
179185
end
180186

181187
def specs_by_name(name)
182-
@specs[name].values
188+
@specs[name]&.values || EMPTY_SEARCH
183189
end
184190

185191
EMPTY_SEARCH = [].freeze
@@ -190,11 +196,11 @@ def search_by_spec(spec)
190196
end
191197

192198
def find_by_spec(spec)
193-
@specs[spec.name][spec.full_name]
199+
@specs[spec.name]&.fetch(spec.full_name, nil)
194200
end
195201

196202
def exist?(spec)
197-
@specs[spec.name].key?(spec.full_name)
203+
@specs[spec.name]&.key?(spec.full_name)
198204
end
199205
end
200206
end

0 commit comments

Comments
 (0)