Skip to content

Commit

Permalink
Improve performance of Array#& by choosing the smallest of 2 arrays t…
Browse files Browse the repository at this point in the history
…o create a Hash
  • Loading branch information
andrykonchin committed Jan 18, 2023
1 parent 50176bf commit 5264d2f
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 7 deletions.
2 changes: 2 additions & 0 deletions spec/ruby/core/array/intersect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
it 'returns false' do
[0, 1, 2].intersect?([3, 4]).should == false
[3, 4].intersect?([0, 1, 2]).should == false
[3, 4].intersect?([]).should == false
[].intersect?([0, 1, 2]).should == false
end
end
end
Expand Down
11 changes: 7 additions & 4 deletions spec/ruby/core/array/shared/intersection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,20 @@
obj2 = mock('2')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.should_receive(:eql?).at_least(1).and_return(true)
obj1.stub!(:eql?).and_return(true)
obj2.stub!(:eql?).and_return(true)

[obj1].send(@method, [obj2]).should == [obj1]
[obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj1]
# we cannot expect some particular object in the result array
# because it's an implementation details which array to iterate and both obj1 and obj2 is a correct result
[obj1].send(@method, [obj2]).size.should == 1
[obj1, obj1, obj2, obj2].send(@method, [obj2]).size.should == 1

obj1 = mock('3')
obj2 = mock('4')
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.should_receive(:eql?).at_least(1).and_return(false)
obj1.stub!(:eql?).and_return(false)
obj2.stub!(:eql?).and_return(false)

[obj1].send(@method, [obj2]).should == []
[obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj2]
Expand Down
11 changes: 8 additions & 3 deletions src/main/ruby/truffleruby/core/array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,14 @@ def self.try_convert(obj)

def &(other)
other = Truffle::Type.coerce_to other, Array, :to_ary
return [] if size == 0 || other.size == 0

h = {}
other.each { |e| h[e] = true }
select { |x| h.delete x }
shorter, longer = size > other.size ? [other, self] : [self, other]

shorter_set = {}
shorter.each { |e| shorter_set[e] = true }

longer.select { |e| shorter_set.delete e }
end

def |(other)
Expand Down Expand Up @@ -615,6 +619,7 @@ def inspect
alias_method :to_s, :inspect

def intersect?(other)
other = Truffle::Type.coerce_to other, Array, :to_ary
return false if size == 0 || other.size == 0

shorter, longer = size > other.size ? [other, self] : [self, other]
Expand Down

0 comments on commit 5264d2f

Please sign in to comment.