@@ -509,41 +509,73 @@ private[collection] object NewRedBlackTree {
509
509
* works on the current implementation of the Scala compiler).
510
510
*
511
511
* An alternative is to implement the these classes using plain old Java code...
512
+ *
513
+ * Mutability
514
+ * This implementation encodes both mutable and immutable trees.
515
+ * Mutable trees are never exposed to the user code but we get significant reductions in both CPU and allocations
516
+ * by maintaining a mutable tree during internal operations, e.g. a builder building a Tree, and the other bulk
517
+ * API such as filter or ++
518
+ *
519
+ * Mutable trees are only used within the confines of this bulk operation and not shared
520
+ * Mutable trees may transition to become immutable by calling beforePublish
521
+ * Mutable trees may have child nodes (left and right) which are immutable Trees (this promotes structural sharing)
522
+ *
523
+ * Immutable trees may only child nodes (left and right) which are immutable Trees, and as such the immutable
524
+ * trees the entire transitive subtree is immutable
525
+ *
526
+ * Colour, mutablity and size encoding
527
+ * The colour of the Tree, its mutablity and size are all encoded in the _count field
528
+ * The colour is encoded in the top bit (31) of the _count. This allows a mutable tree to change colour without
529
+ * additional allocation
530
+ * The mutable trees always have bits 0 .. 30 (inclusive) set to 0
531
+ * The immutable trees always have bits 0 .. 30 containing the size of the transitive subtree
532
+ *
533
+ * Naming
534
+ * All of the methods that can yield a mutable result have "mutable" on their name, and generally there
535
+ * is another method similarly named with doesn't. This is to aid safety and to reduce the cognitive load when
536
+ * reviewing changes. e.g.
537
+ * def upd(...) will update an immutable Tree, producing an immutable Tree
538
+ * def mutableUpd(...) will update a mutable or immutable Tree and may return a mutable or immutable Tree
539
+ * a method that has mutable in its name may return a immutable tree if the operation can reuse the existing tree
540
+ *
512
541
*/
513
- final class Tree [A , + B ](
542
+ private [immutable] final class Tree [A , + B ](
514
543
@ (inline @ getter @ setter) private var _key : A ,
515
544
@ (inline @ getter @ setter) private var _value : AnyRef ,
516
545
@ (inline @ getter @ setter) private var _left : Tree [A , _],
517
546
@ (inline @ getter @ setter) private var _right : Tree [A , _],
518
547
@ (inline @ getter @ setter) private var _count : Int )
519
548
{
520
- def isMutable : Boolean = (_count & 0x7FFFFFFF ) == 0
549
+ private [ NewRedBlackTree ] def isMutable : Boolean = (_count & 0x7FFFFFFF ) == 0
521
550
// read only APIs
522
- @ `inline` final def count = {
551
+ @ `inline` private [ NewRedBlackTree ] final def count = {
523
552
// devTimeAssert((_count & 0x7FFFFFFF) != 0)
524
553
_count & 0x7FFFFFFF
525
554
}
526
555
// inlined here to avoid outer object null checks
527
- @ `inline` final def sizeOf (tree: Tree [_,_]) = if (tree eq null ) 0 else tree.count
528
- @ `inline` final def key = _key
529
- @ `inline` final def value = _value.asInstanceOf [B ]
530
- @ `inline` final def left = _left.asInstanceOf [Tree [A , B ]]
531
- @ `inline` final def right = _right.asInstanceOf [Tree [A , B ]]
532
- @ `inline` final def isBlack = _count < 0
533
- @ `inline` final def isRed = _count >= 0
556
+ @ `inline` private [NewRedBlackTree ] final def sizeOf (tree: Tree [_,_]) = if (tree eq null ) 0 else tree.count
557
+ @ `inline` private [immutable] final def key = _key
558
+ @ `inline` private [immutable] final def value = _value.asInstanceOf [B ]
559
+ // Note - in 2.13 this should be private[RedBlackTree] as its only needed or the 2.12 Old RedBlackTree
560
+ @ `inline` private [immutable] final def left = _left.asInstanceOf [Tree [A , B ]]
561
+ // Note - in 2.13 this should be private[RedBlackTree] as its only needed or the 2.12 Old RedBlackTree
562
+ @ `inline` private [immutable] final def right = _right.asInstanceOf [Tree [A , B ]]
563
+ // Note - only used in tests outside RedBlackTree
564
+ @ `inline` private [immutable] final def isBlack = _count < 0
565
+ // Note - only used in tests outside RedBlackTree
566
+ @ `inline` private [immutable] final def isRed = _count >= 0
534
567
535
568
override def toString : String = s " ${if (isRed) " RedTree" else " BlackTree" }( $key, $value, $left, $right) "
536
569
537
570
@ `inline` private def initialCount = _count & 0x80000000
538
- @ `inline` def colourBit = 0x80000000
539
- @ `inline` def initialBlackCount = 0x80000000
540
- @ `inline` def initialRedCount = 0
571
+ @ `inline` private [ NewRedBlackTree ] def colourBit = 0x80000000
572
+ @ `inline` private [ NewRedBlackTree ] def initialBlackCount = 0x80000000
573
+ @ `inline` private [ NewRedBlackTree ] def initialRedCount = 0
541
574
542
575
// mutable APIs
543
- @ `inline` def mutable = (_count & 0x7FFFFFFF ) == 0
544
- def makeImmutable : Tree [A , B ] = {
576
+ private [NewRedBlackTree ] def makeImmutable : Tree [A , B ] = {
545
577
def makeImmutableImpl () = {
546
- if (mutable ) {
578
+ if (isMutable ) {
547
579
var size = 1
548
580
if (_left ne null ) {
549
581
_left.makeImmutable
@@ -561,15 +593,15 @@ private[collection] object NewRedBlackTree {
561
593
this
562
594
}
563
595
564
- def mutableBlack : Tree [A , B ] = {
596
+ private [ NewRedBlackTree ] def mutableBlack : Tree [A , B ] = {
565
597
if (isBlack) this
566
- else if (mutable ) {
598
+ else if (isMutable ) {
567
599
_count = initialBlackCount
568
600
this
569
601
}
570
602
else new Tree (_key, _value, _left, _right, initialBlackCount)
571
603
}
572
- // def mutableRed: Tree[A, B] = {
604
+ // private[NewRedBlackTree] def mutableRed: Tree[A, B] = {
573
605
// if (isRed) this
574
606
// else if (mutable) {
575
607
// _count = initialRedCount
@@ -579,93 +611,93 @@ private[collection] object NewRedBlackTree {
579
611
// }
580
612
// Note - in 2.13 remove his method
581
613
// due to the handling of keys in 2.13 we never replace a key
582
- def mutableWithK [B1 >: B ](newKey : A ): Tree [A , B1 ] = {
614
+ private [ NewRedBlackTree ] def mutableWithK [B1 >: B ](newKey : A ): Tree [A , B1 ] = {
583
615
if (newKey.asInstanceOf [AnyRef ] eq _key.asInstanceOf [AnyRef ]) this
584
- else if (mutable ) {
616
+ else if (isMutable ) {
585
617
_key = newKey
586
618
this
587
619
} else new Tree (newKey, _value.asInstanceOf [AnyRef ], _left, _right, initialCount)
588
620
}
589
- def mutableWithV [B1 >: B ](newValue : B1 ): Tree [A , B1 ] = {
621
+ private [ NewRedBlackTree ] def mutableWithV [B1 >: B ](newValue : B1 ): Tree [A , B1 ] = {
590
622
if (newValue.asInstanceOf [AnyRef ] eq _value.asInstanceOf [AnyRef ]) this
591
- else if (mutable ) {
623
+ else if (isMutable ) {
592
624
_value = newValue.asInstanceOf [AnyRef ]
593
625
this
594
626
} else new Tree (_key, newValue.asInstanceOf [AnyRef ], _left, _right, initialCount)
595
627
}
596
628
// Note - in 2.13 remove his method
597
629
// due to the handling of keys in 2.13 we never replace a key
598
- def mutableWithKV [B1 >: B ](newKey : A , newValue : B1 ): Tree [A , B1 ] = {
630
+ private [ NewRedBlackTree ] def mutableWithKV [B1 >: B ](newKey : A , newValue : B1 ): Tree [A , B1 ] = {
599
631
if ((newKey.asInstanceOf [AnyRef ] eq _key.asInstanceOf [AnyRef ]) &&
600
632
(newValue.asInstanceOf [AnyRef ] eq _value.asInstanceOf [AnyRef ])) this
601
- else if (mutable ) {
633
+ else if (isMutable ) {
602
634
_key = newKey
603
635
_value = newValue.asInstanceOf [AnyRef ]
604
636
this
605
637
} else new Tree (newKey, newValue.asInstanceOf [AnyRef ], _left, _right, initialCount)
606
638
}
607
- def mutableWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
639
+ private [ NewRedBlackTree ] def mutableWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
608
640
if (_left eq newLeft) this
609
- else if (mutable ) {
641
+ else if (isMutable ) {
610
642
_left = newLeft
611
643
this
612
644
} else new Tree (_key, _value, newLeft, _right, initialCount)
613
645
}
614
- def mutableWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
646
+ private [ NewRedBlackTree ] def mutableWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
615
647
if (_right eq newRight) this
616
- else if (mutable ) {
648
+ else if (isMutable ) {
617
649
_right = newRight
618
650
this
619
651
} else new Tree (_key, _value, _left, newRight, initialCount)
620
652
}
621
- def mutableWithLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
653
+ private [ NewRedBlackTree ] def mutableWithLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
622
654
if ((_left eq newLeft) && (_right eq newRight)) this
623
- else if (mutable ) {
655
+ else if (isMutable ) {
624
656
_left = newLeft
625
657
_right = newRight
626
658
this
627
659
} else new Tree (_key, _value, newLeft, newRight, initialCount)
628
660
}
629
- def mutableBlackWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
661
+ private [ NewRedBlackTree ] def mutableBlackWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
630
662
if ((_left eq newLeft) && isBlack) this
631
- else if (mutable ) {
663
+ else if (isMutable ) {
632
664
_count = initialBlackCount
633
665
_left = newLeft
634
666
this
635
667
} else new Tree (_key, _value, newLeft, _right, initialBlackCount)
636
668
}
637
- def mutableBlackWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
669
+ private [ NewRedBlackTree ] def mutableBlackWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
638
670
if ((_right eq newRight) && isBlack) this
639
- else if (mutable ) {
671
+ else if (isMutable ) {
640
672
_count = initialBlackCount
641
673
_right = newRight
642
674
this
643
675
} else new Tree (_key, _value, _left, newRight, initialBlackCount)
644
676
}
645
677
646
- def black : Tree [A , B ] = {
678
+ private [ NewRedBlackTree ] def black : Tree [A , B ] = {
647
679
// assertNotMutable(this)
648
680
if (isBlack) this
649
681
else new Tree (_key, _value, _left, _right, _count ^ colourBit)
650
682
}
651
- def red : Tree [A , B ] = {
683
+ private [ NewRedBlackTree ] def red : Tree [A , B ] = {
652
684
// assertNotMutable(this)
653
685
if (isRed) this
654
686
else new Tree (_key, _value, _left, _right, _count ^ colourBit)
655
687
}
656
- def withKV [B1 >: B ](newKey : A , newValue : B1 ): Tree [A , B1 ] = {
688
+ private [ NewRedBlackTree ] def withKV [B1 >: B ](newKey : A , newValue : B1 ): Tree [A , B1 ] = {
657
689
// assertNotMutable(this)
658
690
if ((newKey.asInstanceOf [AnyRef ] eq _key.asInstanceOf [AnyRef ]) &&
659
691
(newValue.asInstanceOf [AnyRef ] eq _value.asInstanceOf [AnyRef ])) this
660
692
else new Tree (newKey, newValue.asInstanceOf [AnyRef ], _left, _right, _count)
661
693
}
662
- def withV [B1 >: B ](newValue : B1 ): Tree [A , B1 ] = {
694
+ private [ NewRedBlackTree ] def withV [B1 >: B ](newValue : B1 ): Tree [A , B1 ] = {
663
695
// assertNotMutable(this)
664
696
if (newValue.asInstanceOf [AnyRef ] eq _value.asInstanceOf [AnyRef ]) this
665
697
else new Tree (_key, newValue.asInstanceOf [AnyRef ], _left, _right, _count)
666
698
}
667
699
668
- def withLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
700
+ private [ NewRedBlackTree ] def withLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
669
701
// assertNotMutable(this)
670
702
// assertNotMutable(newLeft)
671
703
if (newLeft eq _left) this
@@ -674,7 +706,7 @@ private[collection] object NewRedBlackTree {
674
706
new Tree (key, value.asInstanceOf [AnyRef ], newLeft, _right, (_count & colourBit) | size)
675
707
}
676
708
}
677
- def withRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
709
+ private [ NewRedBlackTree ] def withRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
678
710
// assertNotMutable(this)
679
711
// assertNotMutable(newRight)
680
712
if (newRight eq _right) this
@@ -683,7 +715,7 @@ private[collection] object NewRedBlackTree {
683
715
new Tree (key, value.asInstanceOf [AnyRef ], _left, newRight, (_count & colourBit) | size)
684
716
}
685
717
}
686
- def blackWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
718
+ private [ NewRedBlackTree ] def blackWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
687
719
// assertNotMutable(this)
688
720
// assertNotMutable(newLeft)
689
721
if ((newLeft eq _left) && isBlack) this
@@ -692,7 +724,7 @@ private[collection] object NewRedBlackTree {
692
724
new Tree (key, value.asInstanceOf [AnyRef ], newLeft, _right, initialBlackCount | size)
693
725
}
694
726
}
695
- def blackWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
727
+ private [ NewRedBlackTree ] def blackWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
696
728
// assertNotMutable(this)
697
729
// assertNotMutable(newRight)
698
730
if ((newRight eq _right) && isBlack) this
@@ -701,7 +733,7 @@ private[collection] object NewRedBlackTree {
701
733
new Tree (key, value.asInstanceOf [AnyRef ], _left, newRight, initialBlackCount | size)
702
734
}
703
735
}
704
- def withLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
736
+ private [ NewRedBlackTree ] def withLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
705
737
// assertNotMutable(this)
706
738
// assertNotMutable(newLeft)
707
739
// assertNotMutable(newRight)
@@ -712,22 +744,24 @@ private[collection] object NewRedBlackTree {
712
744
}
713
745
}
714
746
}
715
- @ `inline` def initialBlackCount = 0x80000000
716
- @ `inline` def initialRedCount = 0
747
+ @ `inline` private [ NewRedBlackTree ] def initialBlackCount = 0x80000000
748
+ @ `inline` private [ NewRedBlackTree ] def initialRedCount = 0
717
749
718
- @ `inline` def mutableRedTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]) = new Tree [A ,B ](key, value.asInstanceOf [AnyRef ], left, right, initialRedCount)
719
- @ `inline` def mutableBlackTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]) = new Tree [A ,B ](key, value.asInstanceOf [AnyRef ], left, right, initialBlackCount)
750
+ @ `inline` private [ NewRedBlackTree ] def mutableRedTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]) = new Tree [A ,B ](key, value.asInstanceOf [AnyRef ], left, right, initialRedCount)
751
+ @ `inline` private [ NewRedBlackTree ] def mutableBlackTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]) = new Tree [A ,B ](key, value.asInstanceOf [AnyRef ], left, right, initialBlackCount)
720
752
721
753
/** create a new immutable red tree.
722
754
* left and right may be null
723
755
*/
724
- def RedTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = {
756
+ // Note - in 2.13 this should be private[RedBlackTree] as its only needed or the 2.12 Old RedBlackTree
757
+ private [immutable] def RedTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = {
725
758
// assertNotMutable(left)
726
759
// assertNotMutable(right)
727
760
val size = sizeOf(left) + sizeOf(right) + 1
728
761
new Tree (key, value.asInstanceOf [AnyRef ], left, right, initialRedCount | size)
729
762
}
730
- def BlackTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = {
763
+ // Note - in 2.13 this should be private[RedBlackTree] as its only needed or the 2.12 Old RedBlackTree
764
+ private [immutable] def BlackTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = {
731
765
// assertNotMutable(left)
732
766
// assertNotMutable(right)
733
767
val size = sizeOf(left) + sizeOf(right) + 1
0 commit comments