@@ -41,7 +41,7 @@ private[collection] object NewRedBlackTree {
41
41
else if (cmp > 0 ) lookup(tree.right, x)
42
42
else tree
43
43
}
44
- private [immutable] abstract class Helper [A ] {
44
+ private [immutable] abstract class Helper [A ]( implicit val ordering : Ordering [ A ]) {
45
45
def beforePublish [B ](tree : Tree [A , B ]): Tree [A , B ] = {
46
46
if (tree eq null ) tree
47
47
else {
@@ -52,13 +52,15 @@ private[collection] object NewRedBlackTree {
52
52
}
53
53
/** Create a new balanced tree where `newLeft` replaces `tree.left`.
54
54
* tree and newLeft are never null */
55
- protected [this ] def mutableBalanceLeft [A , B , B1 >: B ](tree : Tree [A , B ], newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
55
+ protected [this ] final def mutableBalanceLeft [A , B , B1 >: B ](tree : Tree [A , B ], newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
56
56
// Parameter trees
57
57
// tree | newLeft
58
58
// -- KV R | nl.L nl.KV nl.R
59
59
// | nl.R.L nl.R.KV nl.R.R
60
- if (tree.left eq newLeft) tree
61
- else if (newLeft.isRed) {
60
+ // Note - unlike the immutable trees we can't consider tree.left eq newLeft
61
+ // as the balance operations may mutate the same object
62
+ // but that check was mostly to avoid the object creation
63
+ if (newLeft.isRed) {
62
64
val newLeft_left = newLeft.left
63
65
val newLeft_right = newLeft.right
64
66
if (isRedTree(newLeft_left)) {
@@ -93,13 +95,15 @@ private[collection] object NewRedBlackTree {
93
95
}
94
96
/** Create a new balanced tree where `newRight` replaces `tree.right`.
95
97
* tree and newRight are never null */
96
- protected [this ] def mutableBalanceRight [A , B , B1 >: B ](tree : Tree [A , B ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
98
+ protected [this ] final def mutableBalanceRight [A , B , B1 >: B ](tree : Tree [A , B ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
97
99
// Parameter trees
98
100
// tree | newRight
99
101
// L KV -- | nr.L nr.KV nr.R
100
102
// | nr.L.L nr.L.KV nr.L.R
101
- if (tree.right eq newRight) tree
102
- else if (newRight.isRed) {
103
+ // Note - unlike the immutable trees we can't consider tree.right eq newRight
104
+ // as the balance operations may mutate the same object
105
+ // but that check was mostly to avoid the object creation
106
+ if (newRight.isRed) {
103
107
val newRight_left = newRight.left
104
108
if (isRedTree(newRight_left)) {
105
109
// RED
@@ -136,11 +140,7 @@ private[collection] object NewRedBlackTree {
136
140
}
137
141
}
138
142
private [immutable] class SetHelper [A ](implicit ordering : Ordering [A ]) extends Helper [A ] {
139
- def addMutable (tree : Tree [A , Any ], k : A ): Tree [A , Any ] = {
140
- mutableUpd(tree, k)
141
- }
142
-
143
- protected [this ] def mutableUpd (tree : Tree [A , Any ], k : A ): Tree [A , Any ] =
143
+ protected [this ] final def mutableUpd (tree : Tree [A , Any ], k : A ): Tree [A , Any ] =
144
144
if (tree eq null ) {
145
145
mutableRedTree(k, (), null , null )
146
146
} else if (k.asInstanceOf [AnyRef ] eq tree.key.asInstanceOf [AnyRef ]) {
@@ -155,12 +155,7 @@ private[collection] object NewRedBlackTree {
155
155
}
156
156
}
157
157
private [immutable] class MapHelper [A , B ](implicit ordering : Ordering [A ]) extends Helper [A ] {
158
-
159
- def addMutable (tree : Tree [A , B ], k : A , v : B ): Tree [A , B ] = {
160
- mutableUpd(tree, k, v)
161
- }
162
-
163
- protected [this ] def mutableUpd [B1 >: B ](tree : Tree [A , B ], k : A , v : B1 ): Tree [A , B1 ] =
158
+ protected [this ] final def mutableUpd [B1 >: B ](tree : Tree [A , B ], k : A , v : B1 ): Tree [A , B1 ] =
164
159
if (tree eq null ) {
165
160
mutableRedTree(k, v, null , null )
166
161
} else if (k.asInstanceOf [AnyRef ] eq tree.key.asInstanceOf [AnyRef ]) {
@@ -330,37 +325,36 @@ private[collection] object NewRedBlackTree {
330
325
// | nl.R.L nl.R.KV nl.R.R
331
326
if (tree.left eq newLeft) tree
332
327
else {
333
- val tree_key = tree.key
334
- val tree_value = tree.value
335
- val tree_right = tree.right
336
- if (isRedTree(newLeft)) {
328
+ if (newLeft.isRed) {
337
329
val newLeft_left = newLeft.left
338
330
val newLeft_right = newLeft.right
339
331
if (isRedTree(newLeft_left)) {
340
332
// RED
341
333
// black(nl.L) nl.KV black
342
334
// nl.R KV R
343
- RedTree (newLeft.key, newLeft.value,
344
- newLeft_left.black,
345
- BlackTree (tree_key, tree_value, newLeft_right, tree_right))
335
+ val resultLeft = newLeft_left.black
336
+ val resultRight = tree.blackWithLeft(newLeft_right)
337
+
338
+ newLeft.withLeftRight(resultLeft, resultRight)
346
339
} else if (isRedTree(newLeft_right)) {
347
340
// RED
348
341
// black nl.R.KV black
349
342
// nl.L nl.KV nl.R.L nl.R.R KV R
350
- RedTree (newLeft_right.key, newLeft_right.value,
351
- BlackTree (newLeft.key, newLeft.value, newLeft_left, newLeft_right.left),
352
- BlackTree (tree_key, tree_value, newLeft_right.right, tree_right))
343
+ val newLeft_right_right = newLeft_right.right
344
+
345
+ val resultLeft = newLeft.blackWithRight(newLeft_right.left)
346
+ val resultRight = tree.blackWithLeft(newLeft_right_right)
347
+
348
+ newLeft_right.withLeftRight(resultLeft, resultRight)
353
349
} else {
354
350
// tree
355
351
// newLeft KV R
356
- mkTree(isBlack(tree), tree_key, tree_value,
357
- newLeft,
358
- tree_right)
352
+ tree.withLeft(newLeft)
359
353
}
360
354
} else {
361
355
// tree
362
356
// newLeft KV R
363
- mkTree(isBlack( tree), tree_key, tree_value, newLeft, tree_right )
357
+ tree.withLeft( newLeft)
364
358
}
365
359
}
366
360
}
@@ -372,35 +366,36 @@ private[collection] object NewRedBlackTree {
372
366
// | nr.L.L nr.L.KV nr.L.R
373
367
if (tree.right eq newRight) tree
374
368
else {
375
- val tree_key = tree.key
376
- val tree_value = tree.value
377
- val tree_left = tree.left
378
- if (isRedTree(newRight)) {
369
+ if (newRight.isRed) {
379
370
val newRight_left = newRight.left
380
- val newRight_right = newRight.right
381
371
if (isRedTree(newRight_left)) {
382
372
// RED
383
373
// black nr.L.KV black
384
374
// L KV nr.L.L nr.L.R nr.KV nr.R
385
- RedTree (newRight_left.key, newRight_left.value,
386
- BlackTree (tree_key, tree_value, tree_left, newRight_left.left),
387
- BlackTree (newRight.key, newRight.value, newRight_left.right, newRight_right))
388
- } else if (isRedTree(newRight_right)) {
389
- // RED
390
- // black nr.KV black(nr.R)
391
- // L KV nr.L
392
- RedTree (newRight.key, newRight.value,
393
- BlackTree (tree_key, tree_value, tree_left, newRight_left),
394
- newRight_right.black)
375
+ val resultLeft = tree.blackWithRight(newRight_left.left)
376
+ val resultRight = newRight.blackWithLeft(newRight_left.right)
377
+
378
+ newRight_left.withLeftRight(resultLeft, resultRight)
395
379
} else {
396
- // tree
397
- // L KV newRight
398
- mkTree(isBlack(tree), tree_key, tree_value, tree_left, newRight)
380
+ val newRight_right = newRight.right
381
+ if (isRedTree(newRight_right)) {
382
+ // RED
383
+ // black nr.KV black(nr.R)
384
+ // L KV nr.L
385
+ val resultLeft = tree.blackWithRight(newRight_left)
386
+ val resultRight = newRight_right.black
387
+
388
+ newRight.withLeftRight(resultLeft, resultRight)
389
+ } else {
390
+ // tree
391
+ // L KV newRight
392
+ tree.withRight(newRight)
393
+ }
399
394
}
400
395
} else {
401
396
// tree
402
397
// L KV newRight
403
- mkTree(isBlack( tree), tree_key, tree_value, tree_left, newRight)
398
+ tree.withRight( newRight)
404
399
}
405
400
}
406
401
}
@@ -409,16 +404,16 @@ private[collection] object NewRedBlackTree {
409
404
RedTree (k, v, null , null )
410
405
} else if (k.asInstanceOf [AnyRef ] eq tree.key.asInstanceOf [AnyRef ]) {
411
406
if (overwrite && (v.asInstanceOf [AnyRef ] ne tree.value.asInstanceOf [AnyRef ]))
412
- mkTree(isBlackTree( tree), tree .key, v, tree.left, tree.right )
407
+ tree.withKV( tree.key, v)
413
408
else tree
414
409
} else {
415
410
val cmp = ordering.compare(k, tree.key)
416
411
if (cmp < 0 )
417
412
balanceLeft(tree, upd(tree.left, k, v, overwrite))
418
413
else if (cmp > 0 )
419
414
balanceRight(tree, upd(tree.right, k, v, overwrite))
420
- else if (( overwrite && (v. asInstanceOf [ AnyRef ] ne tree.value. asInstanceOf [ AnyRef ])) || k != tree.key)
421
- mkTree(isBlackTree( tree), k, v, tree.left, tree.right )
415
+ else if (overwrite || k != tree.key)
416
+ tree.withKV( k, v)
422
417
else tree
423
418
}
424
419
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 ) {
@@ -516,7 +511,10 @@ private[collection] object NewRedBlackTree {
516
511
@ (inline @ getter @ setter) private var _count : Int )
517
512
{
518
513
// read only APIs
519
- @ `inline` final def count = _count & 0x7FFFFFFF
514
+ @ `inline` final def count = {
515
+ devTimeAssert((_count & 0x7FFFFFFF ) != 0 )
516
+ _count & 0x7FFFFFFF
517
+ }
520
518
@ `inline` final def key = _key
521
519
@ `inline` final def value = _value.asInstanceOf [B ]
522
520
@ `inline` final def left = _left.asInstanceOf [Tree [A , B ]]
@@ -527,6 +525,7 @@ private[collection] object NewRedBlackTree {
527
525
override def toString : String = s " ${if (isRed) " RedTree" else " BlackTree" }( $key, $value, $left, $right) "
528
526
529
527
@ `inline` private def initialCount = _count & 0x80000000
528
+ @ `inline` def colourBit = 0x80000000
530
529
@ `inline` def initialBlackCount = 0x80000000
531
530
@ `inline` def initialRedCount = 0
532
531
@@ -549,7 +548,6 @@ private[collection] object NewRedBlackTree {
549
548
this
550
549
}
551
550
makeImmutableImpl()
552
- // TODO call releaseFence after backported
553
551
this
554
552
}
555
553
@@ -561,14 +559,14 @@ private[collection] object NewRedBlackTree {
561
559
}
562
560
else new Tree (_key, _value, _left, _right, initialBlackCount)
563
561
}
564
- def mutableRed : Tree [A , B ] = {
565
- if (isRed) this
566
- else if (mutable) {
567
- _count = initialRedCount
568
- this
569
- }
570
- else new Tree (_key, _value, _left, _right, initialRedCount)
571
- }
562
+ // def mutableRed: Tree[A, B] = {
563
+ // if (isRed) this
564
+ // else if (mutable) {
565
+ // _count = initialRedCount
566
+ // this
567
+ // }
568
+ // else new Tree(_key, _value, _left, _right, initialRedCount)
569
+ // }
572
570
def mutableWithKV [B1 >: B ](key : A , value : B1 ): Tree [A , B1 ] = {
573
571
if (mutable) {
574
572
_key = key
@@ -609,21 +607,52 @@ private[collection] object NewRedBlackTree {
609
607
this
610
608
} else new Tree (_key, _value, _left, newRight, initialBlackCount)
611
609
}
612
- // def mutableBlackWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
613
- // if (mutable) {
614
- // _count = initialBlackCount
615
- // _left = newLeft
616
- // _right = newRight
617
- // this
618
- // } else new Tree(_key, _value, newLeft, newRight, initialBlackCount)
619
- // }
620
- // immutable APIs
621
- def black : Tree [A , B ] = mutableBlack.makeImmutable
622
- def red : Tree [A , B ] = mutableRed.makeImmutable
623
- def withKV [B1 >: B ](key : A , value : B1 ): Tree [A , B1 ] = mutableWithKV(key,value).makeImmutable
624
- def withLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = mutableWithLeft(newLeft).makeImmutable
625
- def withRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = mutableWithRight(newRight).makeImmutable
626
- def withLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = mutableWithLeftRight(newLeft, newRight).makeImmutable
610
+
611
+ def black : Tree [A , B ] = {
612
+ assertNotMutable(this )
613
+ if (isBlack) this
614
+ else new Tree (_key, _value, _left, _right, _count ^ colourBit)
615
+ }
616
+ def red : Tree [A , B ] = {
617
+ assertNotMutable(this )
618
+ if (isRed) this
619
+ else new Tree (_key, _value, _left, _right, _count ^ colourBit)
620
+ }
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)
624
+ }
625
+ 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)
630
+ }
631
+ 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)
636
+ }
637
+ 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)
642
+ }
643
+ 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)
648
+ }
649
+ 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)
655
+ }
627
656
}
628
657
@ `inline` def initialBlackCount = 0x80000000
629
658
@ `inline` def initialRedCount = 0
@@ -633,10 +662,28 @@ private[collection] object NewRedBlackTree {
633
662
634
663
/** create a new immutable red tree.
635
664
* left and right may be null
636
- * TODO - make the callers able to cope with mutability
637
665
*/
638
- @ `inline` def RedTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = mutableRedTree(key, value, left, right).makeImmutable
639
- @ `inline` def BlackTree [A , B ](key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]): Tree [A , B ] = mutableBlackTree(key, value, left, right).makeImmutable
666
+ 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)
669
+ val size = sizeOf(left) + sizeOf(right) + 1
670
+ new Tree (key, value.asInstanceOf [AnyRef ], left, right, initialRedCount | size)
671
+ }
672
+ 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)
675
+ val size = sizeOf(left) + sizeOf(right) + 1
676
+ new Tree (key, value.asInstanceOf [AnyRef ], left, right, initialBlackCount | size)
677
+ }
678
+ @ `inline` private def sizeOf (tree: Tree [_,_]) = if (tree eq null ) 0 else tree.count
679
+ // 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 )
640
687
641
688
private [this ] abstract class TreeIterator [A , B , R ](root : Tree [A , B ], start : Option [A ])(protected implicit val ordering : Ordering [A ]) extends Iterator [R ] {
642
689
protected [this ] def nextResult (tree : Tree [A , B ]): R
0 commit comments