From 5264d2fc4c741879ed918e06a9b10c74097ac2a9 Mon Sep 17 00:00:00 2001 From: Andrew Konchin Date: Wed, 18 Jan 2023 16:46:42 +0200 Subject: [PATCH] Improve performance of Array#& by choosing the smallest of 2 arrays to create a Hash --- spec/ruby/core/array/intersect_spec.rb | 2 ++ spec/ruby/core/array/shared/intersection.rb | 11 +++++++---- src/main/ruby/truffleruby/core/array.rb | 11 ++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb index 773e44c0734c..d415069dcfc0 100644 --- a/spec/ruby/core/array/intersect_spec.rb +++ b/spec/ruby/core/array/intersect_spec.rb @@ -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 diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb index 49849b08c231..64e143ad0da5 100644 --- a/spec/ruby/core/array/shared/intersection.rb +++ b/spec/ruby/core/array/shared/intersection.rb @@ -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] diff --git a/src/main/ruby/truffleruby/core/array.rb b/src/main/ruby/truffleruby/core/array.rb index 2c07ca0ca375..37261bfd20d4 100644 --- a/src/main/ruby/truffleruby/core/array.rb +++ b/src/main/ruby/truffleruby/core/array.rb @@ -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) @@ -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]