Skip to content

Commit dd7b6cb

Browse files
committed
use the TreeMapBuilder
- align the mutable and immutable APIs - make immutable APIs that dont use mutable ones - add some dev time assertions - Builders extend Helpers
1 parent 33f4a2b commit dd7b6cb

File tree

3 files changed

+158
-142
lines changed

3 files changed

+158
-142
lines changed

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

Lines changed: 129 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ private[collection] object NewRedBlackTree {
4141
else if (cmp > 0) lookup(tree.right, x)
4242
else tree
4343
}
44-
private[immutable] abstract class Helper[A] {
44+
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
4747
else {
@@ -52,13 +52,15 @@ private[collection] object NewRedBlackTree {
5252
}
5353
/** Create a new balanced tree where `newLeft` replaces `tree.left`.
5454
* 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] = {
5656
// Parameter trees
5757
// tree | newLeft
5858
// -- KV R | nl.L nl.KV nl.R
5959
// | 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) {
6264
val newLeft_left = newLeft.left
6365
val newLeft_right = newLeft.right
6466
if (isRedTree(newLeft_left)) {
@@ -93,13 +95,15 @@ private[collection] object NewRedBlackTree {
9395
}
9496
/** Create a new balanced tree where `newRight` replaces `tree.right`.
9597
* 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] = {
9799
// Parameter trees
98100
// tree | newRight
99101
// L KV -- | nr.L nr.KV nr.R
100102
// | 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) {
103107
val newRight_left = newRight.left
104108
if (isRedTree(newRight_left)) {
105109
// RED
@@ -136,11 +140,7 @@ private[collection] object NewRedBlackTree {
136140
}
137141
}
138142
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] =
144144
if (tree eq null) {
145145
mutableRedTree(k, (), null, null)
146146
} else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
@@ -155,12 +155,7 @@ private[collection] object NewRedBlackTree {
155155
}
156156
}
157157
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] =
164159
if (tree eq null) {
165160
mutableRedTree(k, v, null, null)
166161
} else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
@@ -330,37 +325,36 @@ private[collection] object NewRedBlackTree {
330325
// | nl.R.L nl.R.KV nl.R.R
331326
if (tree.left eq newLeft) tree
332327
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) {
337329
val newLeft_left = newLeft.left
338330
val newLeft_right = newLeft.right
339331
if (isRedTree(newLeft_left)) {
340332
// RED
341333
// black(nl.L) nl.KV black
342334
// 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)
346339
} else if (isRedTree(newLeft_right)) {
347340
// RED
348341
// black nl.R.KV black
349342
// 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)
353349
} else {
354350
// tree
355351
// newLeft KV R
356-
mkTree(isBlack(tree), tree_key, tree_value,
357-
newLeft,
358-
tree_right)
352+
tree.withLeft(newLeft)
359353
}
360354
} else {
361355
// tree
362356
// newLeft KV R
363-
mkTree(isBlack(tree), tree_key, tree_value, newLeft, tree_right)
357+
tree.withLeft(newLeft)
364358
}
365359
}
366360
}
@@ -372,35 +366,36 @@ private[collection] object NewRedBlackTree {
372366
// | nr.L.L nr.L.KV nr.L.R
373367
if (tree.right eq newRight) tree
374368
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) {
379370
val newRight_left = newRight.left
380-
val newRight_right = newRight.right
381371
if (isRedTree(newRight_left)) {
382372
// RED
383373
// black nr.L.KV black
384374
// 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)
395379
} 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+
}
399394
}
400395
} else {
401396
// tree
402397
// L KV newRight
403-
mkTree(isBlack(tree), tree_key, tree_value, tree_left, newRight)
398+
tree.withRight(newRight)
404399
}
405400
}
406401
}
@@ -409,16 +404,16 @@ private[collection] object NewRedBlackTree {
409404
RedTree(k, v, null, null)
410405
} else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
411406
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)
413408
else tree
414409
} else {
415410
val cmp = ordering.compare(k, tree.key)
416411
if (cmp < 0)
417412
balanceLeft(tree, upd(tree.left, k, v, overwrite))
418413
else if (cmp > 0)
419414
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)
422417
else tree
423418
}
424419
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 {
516511
@(inline @getter @setter) private var _count: Int)
517512
{
518513
// read only APIs
519-
@`inline` final def count = _count & 0x7FFFFFFF
514+
@`inline` final def count = {
515+
devTimeAssert((_count & 0x7FFFFFFF) != 0)
516+
_count & 0x7FFFFFFF
517+
}
520518
@`inline` final def key = _key
521519
@`inline` final def value = _value.asInstanceOf[B]
522520
@`inline` final def left = _left.asInstanceOf[Tree[A, B]]
@@ -527,6 +525,7 @@ private[collection] object NewRedBlackTree {
527525
override def toString: String = s"${if(isRed) "RedTree" else "BlackTree"}($key, $value, $left, $right)"
528526

529527
@`inline` private def initialCount = _count & 0x80000000
528+
@`inline` def colourBit = 0x80000000
530529
@`inline` def initialBlackCount = 0x80000000
531530
@`inline` def initialRedCount = 0
532531

@@ -549,7 +548,6 @@ private[collection] object NewRedBlackTree {
549548
this
550549
}
551550
makeImmutableImpl()
552-
//TODO call releaseFence after backported
553551
this
554552
}
555553

@@ -561,14 +559,14 @@ private[collection] object NewRedBlackTree {
561559
}
562560
else new Tree(_key, _value, _left, _right, initialBlackCount)
563561
}
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+
// }
572570
def mutableWithKV[B1 >: B](key: A, value: B1): Tree[A, B1] = {
573571
if (mutable) {
574572
_key = key
@@ -609,21 +607,52 @@ private[collection] object NewRedBlackTree {
609607
this
610608
} else new Tree(_key, _value, _left, newRight, initialBlackCount)
611609
}
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+
}
627656
}
628657
@`inline` def initialBlackCount = 0x80000000
629658
@`inline` def initialRedCount = 0
@@ -633,10 +662,28 @@ private[collection] object NewRedBlackTree {
633662

634663
/** create a new immutable red tree.
635664
* left and right may be null
636-
* TODO - make the callers able to cope with mutability
637665
*/
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)
640687

641688
private[this] abstract class TreeIterator[A, B, R](root: Tree[A, B], start: Option[A])(protected implicit val ordering: Ordering[A]) extends Iterator[R] {
642689
protected[this] def nextResult(tree: Tree[A, B]): R

0 commit comments

Comments
 (0)