Skip to content

Commit 3d7dde4

Browse files
authored
Merge pull request scala/scala#10683 from som-snytt/issue/12944-hashset-issubset
Handle empty test and NxD in subsetOf [ci: last-only]
2 parents 4c8df1a + 37e07bf commit 3d7dde4

File tree

1 file changed

+25
-34
lines changed

1 file changed

+25
-34
lines changed

library/src/scala/collection/immutable/HashSet.scala

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,10 @@ final class HashSet[A] private[immutable](private[immutable] val rootNode: Bitma
190190
* Stops iterating the first time that f returns `false`.*/
191191
@`inline` private[collection] def foreachWithHashWhile(f: (A, Int) => Boolean): Unit = rootNode.foreachWithHashWhile(f)
192192

193-
def subsetOf(that: Set[A]): Boolean = if (that.isEmpty) true else that match {
193+
def subsetOf(that: Set[A]): Boolean = isEmpty || !that.isEmpty && (that match {
194194
case set: HashSet[A] => rootNode.subsetOf(set.rootNode, 0)
195195
case _ => super.subsetOf(that)
196-
}
196+
})
197197

198198
override def equals(that: Any): Boolean =
199199
that match {
@@ -606,48 +606,37 @@ private final class BitmapIndexedSetNode[A](
606606

607607
if (element0 == element) {
608608
if (this.payloadArity == 2 && this.nodeArity == 0) {
609-
/*
610-
* Create new node with remaining pair. The new node will a) either become the new root
611-
* returned, or b) unwrapped and inlined during returning.
612-
*/
609+
// Create new node with remaining pair. The new node will a) either become the new root
610+
// returned, or b) unwrapped and inlined during returning.
613611
val newDataMap = if (shift == 0) (dataMap ^ bitpos) else bitposFrom(maskFrom(elementHash, 0))
614-
if (index == 0)
615-
return new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(1)), Array(originalHashes(1)), size - 1, improve(originalHashes(1)))
616-
else
617-
return new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(0)), Array(originalHashes(0)), size - 1, improve(originalHashes(0)))
612+
if (index == 0) new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(1)), Array(originalHashes(1)), size - 1, improve(originalHashes(1)))
613+
else new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(0)), Array(originalHashes(0)), size - 1, improve(originalHashes(0)))
618614
}
619-
else return copyAndRemoveValue(bitpos, elementHash)
620-
} else return this
615+
else copyAndRemoveValue(bitpos, elementHash)
616+
}
617+
else this
621618
}
622-
623-
if ((nodeMap & bitpos) != 0) {
619+
else if ((nodeMap & bitpos) != 0) {
624620
val index = indexFrom(nodeMap, mask, bitpos)
625621
val subNode = this.getNode(index)
626-
627622
val subNodeNew = subNode.removed(element, originalHash, elementHash, shift + BitPartitionSize)
628623

629-
if (subNodeNew eq subNode) return this
630-
631-
// cache just in case subNodeNew is a hashCollision node, in which in which case a little arithmetic is avoided
632-
// in Vector#length
633-
val subNodeNewSize = subNodeNew.size
634-
635-
if (subNodeNewSize == 1) {
636-
if (this.size == subNode.size) {
624+
if (subNodeNew eq subNode) this
625+
// if subNodeNew is a hashCollision node, size has cost in Vector#length
626+
else subNodeNew.size match {
627+
case 1 =>
637628
// subNode is the only child (no other data or node children of `this` exist)
638629
// escalate (singleton or empty) result
639-
return subNodeNew.asInstanceOf[BitmapIndexedSetNode[A]]
640-
} else {
630+
if (this.size == subNode.size) subNodeNew.asInstanceOf[BitmapIndexedSetNode[A]]
641631
// inline value (move to front)
642-
return copyAndMigrateFromNodeToInline(bitpos, elementHash, subNode, subNodeNew)
643-
}
644-
} else if (subNodeNewSize > 1) {
645-
// modify current node (set replacement node)
646-
return copyAndSetNode(bitpos, subNode, subNodeNew)
632+
else copyAndMigrateFromNodeToInline(bitpos, elementHash, subNode, subNodeNew)
633+
case subNodeNewSize if subNodeNewSize > 1 =>
634+
// modify current node (set replacement node)
635+
copyAndSetNode(bitpos, subNode, subNodeNew)
636+
case _ => this
647637
}
648638
}
649-
650-
this
639+
else this
651640
}
652641
/** Variant of `removed` which will perform mutation on only the top-level node (`this`), rather than return a new
653642
* node
@@ -999,7 +988,7 @@ private final class BitmapIndexedSetNode[A](
999988
val elementHash = improve(elementUnimprovedHash)
1000989
subNode.contains(payload, elementUnimprovedHash, elementHash, shift + BitPartitionSize)
1001990
}
1002-
} else {
991+
} else ((node.dataMap & bitpos) == 0) && {
1003992
// Node x Node
1004993
val subNode0 = this.getNode(indexFrom(this.nodeMap, bitpos))
1005994
val subNode1 = node.getNode(indexFrom(node.nodeMap, bitpos))
@@ -1428,6 +1417,8 @@ private final class BitmapIndexedSetNode[A](
14281417
override def hashCode(): Int =
14291418
throw new UnsupportedOperationException("Trie nodes do not support hashing.")
14301419

1420+
override def toString: String = f"BitmapIndexedSetNode(size=$size, dataMap=$dataMap%x, nodeMap=$nodeMap%x)" // content=${scala.runtime.ScalaRunTime.stringOf(content)}
1421+
14311422
override def copy(): BitmapIndexedSetNode[A] = {
14321423
val contentClone = content.clone()
14331424
val contentLength = contentClone.length
@@ -2077,7 +2068,7 @@ private[collection] final class HashSetBuilder[A] extends ReusableBuilder[A, Has
20772068
ensureUnaliased()
20782069
val h = elem.##
20792070
val im = improve(h)
2080-
update(rootNode, elem, h, im, 0)
2071+
update(rootNode, elem, originalHash = h, elementHash = im, shift = 0)
20812072
this
20822073
}
20832074

0 commit comments

Comments
 (0)