Skip to content

Commit 9da87e6

Browse files
committed
minor improvements from profiling
1 parent dd7b6cb commit 9da87e6

File tree

2 files changed

+98
-65
lines changed

2 files changed

+98
-65
lines changed

library/src/scala/collection/immutable/RedBlackTree.scala

Lines changed: 89 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ private[collection] object NewRedBlackTree {
4444
private[immutable] abstract class Helper[A](implicit val ordering: Ordering[A]) {
4545
def beforePublish[B](tree: Tree[A, B]): Tree[A, B] = {
4646
if (tree eq null) tree
47-
else {
47+
else if (tree.isMutable) {
4848
val res = tree.mutableBlack.makeImmutable
4949
VM.releaseFence()
5050
res
51-
}
51+
} else tree.black
5252
}
5353
/** Create a new balanced tree where `newLeft` replaces `tree.left`.
5454
* tree and newLeft are never null */
@@ -159,18 +159,14 @@ private[collection] object NewRedBlackTree {
159159
if (tree eq null) {
160160
mutableRedTree(k, v, null, null)
161161
} else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
162-
if (v.asInstanceOf[AnyRef] ne tree.value.asInstanceOf[AnyRef])
163-
tree.mutableWithKV(tree.key, v)
164-
else tree
162+
tree.mutableWithV(v)
165163
} else {
166164
val cmp = ordering.compare(k, tree.key)
167165
if (cmp < 0)
168166
mutableBalanceLeft(tree, mutableUpd(tree.left, k, v))
169167
else if (cmp > 0)
170168
mutableBalanceRight(tree, mutableUpd(tree.right, k, v))
171-
else if (v.asInstanceOf[AnyRef] ne tree.value.asInstanceOf[AnyRef])
172-
tree.mutableWithKV(tree.key, v)
173-
else tree
169+
else tree.mutableWithV(v)
174170
}
175171
}
176172

@@ -403,8 +399,8 @@ private[collection] object NewRedBlackTree {
403399
private[this] def upd[A, B, B1 >: B](tree: Tree[A, B], k: A, v: B1, overwrite: Boolean)(implicit ordering: Ordering[A]): Tree[A, B1] = if (tree eq null) {
404400
RedTree(k, v, null, null)
405401
} else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
406-
if (overwrite && (v.asInstanceOf[AnyRef] ne tree.value.asInstanceOf[AnyRef]))
407-
tree.withKV(tree.key, v)
402+
if (overwrite)
403+
tree.withV(v)
408404
else tree
409405
} else {
410406
val cmp = ordering.compare(k, tree.key)
@@ -414,6 +410,9 @@ private[collection] object NewRedBlackTree {
414410
balanceRight(tree, upd(tree.right, k, v, overwrite))
415411
else if (overwrite || k != tree.key)
416412
tree.withKV(k, v)
413+
//Note - in 2.13 this is
414+
// else if (overwrite) tree.withV(v)
415+
//due to the changes in handling of keys
417416
else tree
418417
}
419418
private[this] def updNth[A, B, B1 >: B](tree: Tree[A, B], idx: Int, k: A, v: B1): Tree[A, B1] = if (tree eq null) {
@@ -510,11 +509,14 @@ private[collection] object NewRedBlackTree {
510509
@(inline @getter @setter) private var _right: Tree[A, _],
511510
@(inline @getter @setter) private var _count: Int)
512511
{
512+
def isMutable: Boolean = (_count & 0x7FFFFFFF) == 0
513513
// read only APIs
514514
@`inline` final def count = {
515-
devTimeAssert((_count & 0x7FFFFFFF) != 0)
515+
//devTimeAssert((_count & 0x7FFFFFFF) != 0)
516516
_count & 0x7FFFFFFF
517517
}
518+
//inlined here to avoid outer object null checks
519+
@`inline` final def sizeOf(tree:Tree[_,_]) = if (tree eq null) 0 else tree.count
518520
@`inline` final def key = _key
519521
@`inline` final def value = _value.asInstanceOf[B]
520522
@`inline` final def left = _left.asInstanceOf[Tree[A, B]]
@@ -567,91 +569,119 @@ private[collection] object NewRedBlackTree {
567569
// }
568570
// else new Tree(_key, _value, _left, _right, initialRedCount)
569571
// }
570-
def mutableWithKV[B1 >: B](key: A, value: B1): Tree[A, B1] = {
571-
if (mutable) {
572-
_key = key
572+
def mutableWithV[B1 >: B](value: B1): Tree[A, B1] = {
573+
if (value.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef]) this
574+
else if (mutable) {
573575
_value = value.asInstanceOf[AnyRef]
574576
this
575-
} else new Tree(key, value.asInstanceOf[AnyRef], _left, _right, _count)
577+
} else new Tree(_key, value.asInstanceOf[AnyRef], _left, _right, _count)
576578
}
577579
def mutableWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
578-
if (mutable) {
580+
if (_left eq newLeft) this
581+
else if (mutable) {
579582
_left = newLeft
580583
this
581584
} else new Tree(_key, _value, newLeft, _right, initialCount)
582585
}
583586
def mutableWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
584-
if (mutable) {
587+
if (_right eq newRight) this
588+
else if (mutable) {
585589
_right = newRight
586590
this
587591
} else new Tree(_key, _value, _left, newRight, initialCount)
588592
}
589593
def mutableWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
590-
if (mutable) {
594+
if ((_left eq newLeft) && (_right eq newRight)) this
595+
else if (mutable) {
591596
_left = newLeft
592597
_right = newRight
593598
this
594599
} else new Tree(_key, _value, newLeft, newRight, initialCount)
595600
}
596601
def mutableBlackWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
597-
if (mutable) {
602+
if ((_left eq newLeft) && isBlack) this
603+
else if (mutable) {
598604
_count = initialBlackCount
599605
_left = newLeft
600606
this
601607
} else new Tree(_key, _value, newLeft, _right, initialBlackCount)
602608
}
603609
def mutableBlackWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
604-
if (mutable) {
610+
if ((_right eq newRight) && isBlack) this
611+
else if (mutable) {
605612
_count = initialBlackCount
606613
_right = newRight
607614
this
608615
} else new Tree(_key, _value, _left, newRight, initialBlackCount)
609616
}
610617

611618
def black: Tree[A, B] = {
612-
assertNotMutable(this)
619+
//assertNotMutable(this)
613620
if (isBlack) this
614621
else new Tree(_key, _value, _left, _right, _count ^ colourBit)
615622
}
616623
def red: Tree[A, B] = {
617-
assertNotMutable(this)
624+
//assertNotMutable(this)
618625
if (isRed) this
619626
else new Tree(_key, _value, _left, _right, _count ^ colourBit)
620627
}
621-
def withKV[B1 >: B](key: A, value: B1): Tree[A, B1] = {
622-
assertNotMutable(this)
623-
new Tree(key, value.asInstanceOf[AnyRef], _left, _right, _count)
628+
def withKV[B1 >: B](newKey: A, newValue: B1): Tree[A, B1] = {
629+
//assertNotMutable(this)
630+
if ((newKey.asInstanceOf[AnyRef] eq _key.asInstanceOf[AnyRef]) &&
631+
(newValue.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef])) this
632+
else new Tree(newKey, newValue.asInstanceOf[AnyRef], _left, _right, _count)
633+
}
634+
def withV[B1 >: B](newValue: B1): Tree[A, B1] = {
635+
//assertNotMutable(this)
636+
if (newValue.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef]) this
637+
else new Tree(_key, newValue.asInstanceOf[AnyRef], _left, _right, _count)
624638
}
639+
625640
def withLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
626-
assertNotMutable(this)
627-
assertNotMutable(newLeft)
628-
val size = sizeOf(newLeft) + sizeOf(_right) + 1
629-
new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, (_count & colourBit) | size)
641+
//assertNotMutable(this)
642+
//assertNotMutable(newLeft)
643+
if (newLeft eq _left) this
644+
else {
645+
val size = sizeOf(newLeft) + sizeOf(_right) + 1
646+
new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, (_count & colourBit) | size)
647+
}
630648
}
631649
def withRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
632-
assertNotMutable(this)
633-
assertNotMutable(newRight)
634-
val size = sizeOf(_left) + sizeOf(newRight) + 1
635-
new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, (_count & colourBit) | size)
650+
//assertNotMutable(this)
651+
//assertNotMutable(newRight)
652+
if (newRight eq _right) this
653+
else {
654+
val size = sizeOf(_left) + sizeOf(newRight) + 1
655+
new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, (_count & colourBit) | size)
656+
}
636657
}
637658
def blackWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
638-
assertNotMutable(this)
639-
assertNotMutable(newLeft)
640-
val size = sizeOf(newLeft) + sizeOf(_right) + 1
641-
new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialBlackCount | size)
659+
//assertNotMutable(this)
660+
//assertNotMutable(newLeft)
661+
if ((newLeft eq _left) && isBlack) this
662+
else {
663+
val size = sizeOf(newLeft) + sizeOf(_right) + 1
664+
new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialBlackCount | size)
665+
}
642666
}
643667
def blackWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
644-
assertNotMutable(this)
645-
assertNotMutable(newRight)
646-
val size = sizeOf(_left) + sizeOf(newRight) + 1
647-
new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialBlackCount | size)
668+
//assertNotMutable(this)
669+
//assertNotMutable(newRight)
670+
if ((newRight eq _right) && isBlack) this
671+
else {
672+
val size = sizeOf(_left) + sizeOf(newRight) + 1
673+
new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialBlackCount | size)
674+
}
648675
}
649676
def withLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
650-
assertNotMutable(this)
651-
assertNotMutable(newLeft)
652-
assertNotMutable(newRight)
653-
val size = sizeOf(newLeft) + sizeOf(newRight) + 1
654-
new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, (_count & colourBit) | size)
677+
//assertNotMutable(this)
678+
//assertNotMutable(newLeft)
679+
//assertNotMutable(newRight)
680+
if ((newLeft eq _left) && (newRight eq _right)) this
681+
else {
682+
val size = sizeOf(newLeft) + sizeOf(newRight) + 1
683+
new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, (_count & colourBit) | size)
684+
}
655685
}
656686
}
657687
@`inline` def initialBlackCount = 0x80000000
@@ -664,27 +694,27 @@ private[collection] object NewRedBlackTree {
664694
* left and right may be null
665695
*/
666696
def RedTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]): Tree[A, B] = {
667-
assertNotMutable(left)
668-
assertNotMutable(right)
697+
//assertNotMutable(left)
698+
//assertNotMutable(right)
669699
val size = sizeOf(left) + sizeOf(right) + 1
670700
new Tree(key, value.asInstanceOf[AnyRef], left, right, initialRedCount | size)
671701
}
672702
def BlackTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]): Tree[A, B] = {
673-
assertNotMutable(left)
674-
assertNotMutable(right)
703+
//assertNotMutable(left)
704+
//assertNotMutable(right)
675705
val size = sizeOf(left) + sizeOf(right) + 1
676706
new Tree(key, value.asInstanceOf[AnyRef], left, right, initialBlackCount | size)
677707
}
678-
@`inline` private def sizeOf(tree:Tree[_,_]) = if (tree eq null) 0 else tree.count
708+
@`inline` private def sizeOf(tree:Tree[_,_]) = if (tree eq null) 0 else tree.count
679709
//immutable APIs
680-
//assertions - either elide or remove before merge
681-
//
682-
private def devTimeAssert(assertion: Boolean) = {
683-
//uncomment this during developement of the functionality
684-
assert(assertion)
685-
}
686-
private def assertNotMutable(t:Tree[_,_]) = devTimeAssert ((t eq null) || t.count > 0)
687-
710+
//assertions - uncomment decls and callers when changing functionality
711+
// private def devTimeAssert(assertion: Boolean) = {
712+
// //uncomment this during development of the functionality
713+
// assert(assertion)
714+
// }
715+
// private def assertNotMutable(t:Tree[_,_]) = {
716+
// devTimeAssert ((t eq null) || t.count > 0)
717+
// }
688718
private[this] abstract class TreeIterator[A, B, R](root: Tree[A, B], start: Option[A])(protected implicit val ordering: Ordering[A]) extends Iterator[R] {
689719
protected[this] def nextResult(tree: Tree[A, B]): R
690720

library/src/scala/collection/immutable/TreeMap.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import java.io.IOException
1919
import generic._
2020
import immutable.{NewRedBlackTree => RB}
2121
import mutable.Builder
22+
import scala.runtime.AbstractFunction2
2223
import scala.util.hashing.MurmurHash3
2324

2425
/** $factoryInfo
@@ -36,16 +37,18 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] {
3637
extends RB.MapHelper[A, B]
3738
with Builder[(A, B), TreeMap[A, B]] {
3839
type Tree = RB.Tree[A, B]
39-
private [this] var tree:Tree = null
40+
private var tree:Tree = null
4041

4142
def +=(elem: (A, B)): this.type = {
4243
tree = mutableUpd(tree, elem._1, elem._2)
4344
this
4445
}
45-
private object adder extends Function2[A, B, Unit] {
46-
var accumulator :Tree = null
46+
private object adder extends AbstractFunction2[A, B, Unit] {
47+
// we cache tree to avoid the outer access to tree
48+
// in the hot path (apply)
49+
private[this] var accumulator :Tree = null
4750
def addForEach(aTree:Tree, hasForEach: HasForeachEntry[A, B]): Tree = {
48-
accumulator = aTree
51+
accumulator = tree
4952
hasForEach.foreachEntry(this)
5053
val result = accumulator
5154
// be friendly to GC
@@ -54,7 +57,7 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] {
5457
}
5558

5659
override def apply(key: A, value: B): Unit = {
57-
accumulator = RB.update(accumulator, key, value, overwrite = true)
60+
accumulator = mutableUpd(accumulator, key, value)
5861
}
5962
}
6063

@@ -64,7 +67,7 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] {
6467
// for the moment we have to force immutability before the union
6568
// which will waste some time and space
6669
// calling `beforePublish` makes `tree` immutable
67-
case ts: TreeMap[A, B] if ts.ordering eq ordering =>
70+
case ts: TreeMap[A, B] if ts.ordering == ordering =>
6871
if (tree eq null) tree = ts.tree0
6972
else tree = RB.union(beforePublish(tree), ts.tree0)
7073
case that: HasForeachEntry[A, B] =>

0 commit comments

Comments
 (0)