Skip to content

Commit ffb007a

Browse files
committed
🐛 Fix SequenceSet#max(n), cardinality < n <= size
This backports #580 to `v0.5-stable`. When `SequenceSet#max(n)` is called with `n > cardinality`, it _should_ return a duplicate of the whole set. But, `#max(n)` is implemented using `#slice(-n..)`, and (copying the behavior of `Array`), when a slicing starts from an out-of-range index, it returns `nil`. It was using `-[count, size].min` to keep the index from going out-of-range. Prior to 0.6.0, `#size` is the same as `#count`, so it gives incorrect results when the set contains an endless range. `SequenceSet#cardinality` has not been backported to 0.5, so this makes that calculation inline. This change should also give a small performance boost, because it bypasses the complexity of `#slice(range)` and just calls `#dup` (or returns `self` when the set is frozen).
1 parent 9cf6cfe commit ffb007a

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

lib/net/imap/sequence_set.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,13 @@ def disjoint?(other)
755755
# Related: #min, #minmax, #slice
756756
def max(count = nil, star: :*)
757757
if count
758-
slice(-[count, size].min..) || remain_frozen_empty
758+
# n.b: #cardinality has not been backported to 0.5
759+
cardinality = @tuples.sum(@tuples.count) { _2 - _1 }
760+
if cardinality <= count
761+
frozen? ? self : dup
762+
else
763+
slice(-count..) || remain_frozen_empty
764+
end
759765
elsif (val = @tuples.last&.last)
760766
val == STAR_INT ? star : val
761767
end

test/net/imap/test_sequence_set.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,15 @@ def obj.to_sequence_set; 192_168.001_255 end
787787
assert_equal SequenceSet["678"], SequenceSet["345,678"].max(1)
788788
assert_equal SequenceSet["345,678"], SequenceSet["345,678"].max(222)
789789
assert_equal SequenceSet.empty, SequenceSet.new.max(5)
790+
# with different cardinality (150) vs size (200)
791+
set = SequenceSet["101:200,51:150"]
792+
assert_equal SequenceSet["52:200"], set.max(149)
793+
assert_equal SequenceSet["51:200"], set.max(150)
794+
assert_equal SequenceSet["51:200"], set.max(200)
795+
# with different cardinality (2**32) vs count (2**32 - 1)
796+
set = SequenceSet[1..]
797+
assert_equal SequenceSet["2:*"], set.max(2**32 - 1)
798+
assert_equal SequenceSet["1:*"], set.max(2**32)
790799
end
791800

792801
test "#minmax" do

0 commit comments

Comments
 (0)