Skip to content

Commit b648645

Browse files
committed
✨ Add SequenceSet#intersect! for in-place AND
This is simply the mutating version of `#&` or `#intersection`. Although there is room for big performance improvement here, the algorithm remains unchanged, so any performance improvement is small.
1 parent ff6ba0a commit b648645

File tree

4 files changed

+25
-5
lines changed

4 files changed

+25
-5
lines changed

benchmarks/sequence_set-and.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ prelude: |
6565
6666
benchmark:
6767
" L & R": l, r = sets; l & r
68+
"mut! L & R": l, r = sets; l.intersect! r
6869
" L - ~R": l, r = sets; l - ~r
6970
"and0 L - ~R": l, r = sets; l.and0 r
7071
"and0! L - ~R": l, r = sets; l.and0! r

benchmarks/sequence_set-xor.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@ prelude: |
3131
merge(other).subtract(other.subtract(copy.complement!))
3232
end
3333
34-
# TODO: add this as a public method
3534
def intersect!(other) # :nodoc:
3635
modifying!
3736
subtract SequenceSet.new(other).complement!
38-
end
37+
end unless instance_methods.include?(:intersect!)
3938
4039
# (L | R) - (L & R)
4140
def xor2!(other)

lib/net/imap/sequence_set.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ class IMAP
365365
# - #delete?: If the given element is included in the set, removes it and
366366
# returns it; otherwise, returns +nil+.
367367
# - #delete_at: Removes the number at a given offset.
368+
# - #intersect!: In-place set #intersection. Removes numbers that are not
369+
# in the given set; returns +self+.
368370
# - #slice!: Removes the number or consecutive numbers at a given offset or
369371
# range of offsets.
370372
# - #subtract: In-place set #difference. Removes all members of the given
@@ -875,9 +877,7 @@ def -(other) remain_frozen dup.subtract other end
875877
# * <tt>lhs - (lhs - rhs)</tt>
876878
# * <tt>lhs - (lhs ^ rhs)</tt>
877879
# * <tt>lhs ^ (lhs - rhs)</tt>
878-
def &(other)
879-
remain_frozen dup.subtract SequenceSet.new(other).complement!
880-
end
880+
def &(other) remain_frozen dup.intersect! other end
881881
alias intersection :&
882882

883883
# :call-seq:
@@ -1613,6 +1613,22 @@ def complement!
16131613
normalize!
16141614
end
16151615

1616+
# In-place set #intersection. Removes any elements that are missing from
1617+
# +other+ from this set, keeping only the #intersection, and returns
1618+
# +self+.
1619+
#
1620+
# +other+ can be any object that would be accepted by ::new.
1621+
#
1622+
# set = Net::IMAP::SequenceSet.new(1..5)
1623+
# set.intersect! [2, 4, 6]
1624+
# set #=> Net::IMAP::SequenceSet("2,4")
1625+
#
1626+
# Related: #intersection, #intersect?
1627+
def intersect!(other)
1628+
modifying!
1629+
subtract SequenceSet.new(other).complement!
1630+
end
1631+
16161632
# Returns a new SequenceSet with a normalized string representation.
16171633
#
16181634
# The returned set's #string is sorted and deduplicated. Adjacent or

test/net/imap/test_sequence_set.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ def compare_to_reference_set(nums, set, seqset)
8989
assert_equal intersection, lhs - (lhs - rhs)
9090
assert_equal intersection, lhs - (lhs ^ rhs)
9191
assert_equal intersection, lhs ^ (lhs - rhs)
92+
mutable = lhs.dup
93+
assert_equal intersection, mutable.intersect!(rhs)
94+
assert_equal intersection, mutable
9295
end
9396
end
9497

@@ -168,6 +171,7 @@ def compare_to_reference_set(nums, set, seqset)
168171
data "#merge", ->{ _1.merge 1 }
169172
data "#subtract", ->{ _1.subtract 1 }
170173
data "#limit!", ->{ _1.limit! max: 10 }
174+
data "#intersect!", ->{ _1.intersect! SequenceSet[1..100] }
171175
data "#complement!", :complement!
172176
data "#normalize!", :normalize!
173177
test "frozen error message" do |modification|

0 commit comments

Comments
 (0)