@@ -211,19 +211,25 @@ private[collection] object NewRedBlackTree {
211
211
212
212
def tail [A , B ](tree : Tree [A , B ]): Tree [A , B ] = {
213
213
def _tail (tree : Tree [A , B ]): Tree [A , B ] =
214
- if (tree eq null ) throw new NoSuchElementException (" empty tree" )
215
- else if (tree.left eq null ) tree.right
216
- else if (isBlackTree(tree.left)) balLeft(tree.key, tree.value, _tail(tree.left), tree.right)
217
- else RedTree (tree.key, tree.value, _tail(tree.left), tree.right)
214
+ if (tree eq null ) throw new NoSuchElementException (" empty tree" )
215
+ else {
216
+ val tl = tree.left
217
+ if (tl eq null ) tree.right
218
+ else if (tl.isBlack) balLeft(tree, _tail(tl), tree.right)
219
+ else tree.redWithLeft(_tail(tree.left))
220
+ }
218
221
blacken(_tail(tree))
219
222
}
220
223
221
224
def init [A , B ](tree : Tree [A , B ]): Tree [A , B ] = {
222
225
def _init (tree : Tree [A , B ]): Tree [A , B ] =
223
- if (tree eq null ) throw new NoSuchElementException (" empty tree" )
224
- else if (tree.right eq null ) tree.left
225
- else if (isBlackTree(tree.right)) balRight(tree.key, tree.value, tree.left, _init(tree.right))
226
- else RedTree (tree.key, tree.value, tree.left, _init(tree.right))
226
+ if (tree eq null ) throw new NoSuchElementException (" empty tree" )
227
+ else {
228
+ val tr = tree.right
229
+ if (tr eq null ) tree.left
230
+ else if (tr.isBlack) balRight(tree, tree.left, _init(tr))
231
+ else tree.redWithRight(_init(tr))
232
+ }
227
233
blacken(_init(tree))
228
234
}
229
235
@@ -306,7 +312,7 @@ private[collection] object NewRedBlackTree {
306
312
else tree
307
313
}
308
314
309
- def isBlack (tree : Tree [_, _]) = (tree eq null ) || isBlackTree( tree)
315
+ def isBlack (tree : Tree [_, _]) = (tree eq null ) || tree.isBlack
310
316
311
317
@ `inline` private [this ] def isRedTree (tree : Tree [_, _]) = (tree ne null ) && tree.isRed
312
318
@ `inline` private [this ] def isBlackTree (tree : Tree [_, _]) = (tree ne null ) && tree.isBlack
@@ -318,8 +324,10 @@ private[collection] object NewRedBlackTree {
318
324
private [this ] def maybeBlacken [A , B ](t : Tree [A , B ]): Tree [A , B ] =
319
325
if (isBlack(t)) t else if (isRedTree(t.left) || isRedTree(t.right)) t.black else t
320
326
321
- private [this ] def mkTree [A , B ](isBlack : Boolean , k : A , v : B , l : Tree [A , B ], r : Tree [A , B ]) =
322
- if (isBlack) BlackTree (k, v, l, r) else RedTree (k, v, l, r)
327
+ private [this ] def mkTree [A , B ](isBlack : Boolean , key : A , value : B , left : Tree [A , B ], right : Tree [A , B ]) = {
328
+ val sizeAndColour = sizeOf(left) + sizeOf(right) + 1 | (if (isBlack) initialBlackCount else initialRedCount)
329
+ new Tree (key, value.asInstanceOf [AnyRef ], left, right, sizeAndColour)
330
+ }
323
331
324
332
/** Create a new balanced tree where `newLeft` replaces `tree.left`. */
325
333
private [this ] def balanceLeft [A , B1 ](tree : Tree [A , B1 ], newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
@@ -722,6 +730,15 @@ private[collection] object NewRedBlackTree {
722
730
new Tree (key, value.asInstanceOf [AnyRef ], newLeft, _right, initialBlackCount | size)
723
731
}
724
732
}
733
+ private [NewRedBlackTree ] def redWithLeft [B1 >: B ](newLeft : Tree [A , B1 ]): Tree [A , B1 ] = {
734
+ // assertNotMutable(this)
735
+ // assertNotMutable(newLeft)
736
+ if ((newLeft eq _left) && isRed) this
737
+ else {
738
+ val size = sizeOf(newLeft) + sizeOf(_right) + 1
739
+ new Tree (key, value.asInstanceOf [AnyRef ], newLeft, _right, initialRedCount | size)
740
+ }
741
+ }
725
742
private [NewRedBlackTree ] def blackWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
726
743
// assertNotMutable(this)
727
744
// assertNotMutable(newRight)
@@ -731,6 +748,15 @@ private[collection] object NewRedBlackTree {
731
748
new Tree (key, value.asInstanceOf [AnyRef ], _left, newRight, initialBlackCount | size)
732
749
}
733
750
}
751
+ private [NewRedBlackTree ] def redWithRight [B1 >: B ](newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
752
+ // assertNotMutable(this)
753
+ // assertNotMutable(newLeft)
754
+ if ((newRight eq _right) && isRed) this
755
+ else {
756
+ val size = sizeOf(_left) + sizeOf(newRight) + 1
757
+ new Tree (key, value.asInstanceOf [AnyRef ], _left, newRight, initialRedCount | size)
758
+ }
759
+ }
734
760
private [NewRedBlackTree ] def withLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
735
761
// assertNotMutable(this)
736
762
// assertNotMutable(newLeft)
@@ -741,6 +767,26 @@ private[collection] object NewRedBlackTree {
741
767
new Tree (key, value.asInstanceOf [AnyRef ], newLeft, newRight, (_count & colourBit) | size)
742
768
}
743
769
}
770
+ private [NewRedBlackTree ] def redWithLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
771
+ // assertNotMutable(this)
772
+ // assertNotMutable(newLeft)
773
+ // assertNotMutable(newRight)
774
+ if ((newLeft eq _left) && (newRight eq _right) && isRed) this
775
+ else {
776
+ val size = sizeOf(newLeft) + sizeOf(newRight) + 1
777
+ new Tree (key, value.asInstanceOf [AnyRef ], newLeft, newRight, initialRedCount | size)
778
+ }
779
+ }
780
+ private [NewRedBlackTree ] def blackWithLeftRight [B1 >: B ](newLeft : Tree [A , B1 ], newRight : Tree [A , B1 ]): Tree [A , B1 ] = {
781
+ // assertNotMutable(this)
782
+ // assertNotMutable(newLeft)
783
+ // assertNotMutable(newRight)
784
+ if ((newLeft eq _left) && (newRight eq _right) && isBlack) this
785
+ else {
786
+ val size = sizeOf(newLeft) + sizeOf(newRight) + 1
787
+ new Tree (key, value.asInstanceOf [AnyRef ], newLeft, newRight, initialBlackCount | size)
788
+ }
789
+ }
744
790
}
745
791
// see #Tree docs "Colour, mutablity and size encoding"
746
792
// we make these final vals because the optimiser inlines them, without reference to the enclosing module
@@ -956,7 +1002,7 @@ private[collection] object NewRedBlackTree {
956
1002
if ((v2.asInstanceOf [AnyRef ] eq v.asInstanceOf [AnyRef ])
957
1003
&& (l2 eq l)
958
1004
&& (r2 eq r)) t.asInstanceOf [Tree [A , C ]]
959
- else mkTree(isBlackTree(t) , k, v2, l2, r2)
1005
+ else mkTree(t.isBlack , k, v2, l2, r2)
960
1006
}
961
1007
962
1008
def filterEntries [A , B ](t : Tree [A , B ], f : (A , B ) => Boolean ): Tree [A , B ] = if (t eq null ) null else {
@@ -1064,67 +1110,72 @@ private[collection] object NewRedBlackTree {
1064
1110
// Red-Black Trees in a Functional Setting, Chris Okasaki: [[https://wiki.rice.edu/confluence/download/attachments/2761212/Okasaki-Red-Black.pdf]] */
1065
1111
1066
1112
private [this ] def del [A , B ](tree : Tree [A , B ], k : A )(implicit ordering : Ordering [A ]): Tree [A , B ] = if (tree eq null ) null else {
1067
- def delLeft =
1068
- if (isBlackTree(tree.left)) balLeft(tree.key, tree.value, del(tree.left, k), tree.right)
1069
- else RedTree (tree.key, tree.value, del(tree.left, k), tree.right)
1070
- def delRight =
1071
- if (isBlackTree(tree.right)) balRight(tree.key, tree.value, tree.left, del(tree.right, k))
1072
- else RedTree (tree.key, tree.value, tree.left, del(tree.right, k))
1073
1113
val cmp = ordering.compare(k, tree.key)
1074
- if (cmp < 0 ) delLeft
1075
- else if (cmp > 0 ) delRight
1076
- else append(tree.left, tree.right)
1114
+ if (cmp < 0 ) {
1115
+ val newLeft = del(tree.left, k)
1116
+ if (newLeft eq tree.left) tree
1117
+ else if (isBlackTree(tree.left)) balLeft(tree, newLeft, tree.right)
1118
+ else tree.redWithLeft(newLeft)
1119
+ } else if (cmp > 0 ) {
1120
+ val newRight = del(tree.right, k)
1121
+ if (newRight eq tree.right) tree
1122
+ else if (isBlackTree(tree.right)) balRight(tree, tree.left, newRight)
1123
+ else tree.redWithRight(newRight)
1124
+ } else append(tree.left, tree.right)
1077
1125
}
1078
1126
1079
- private [this ] def balance [A , B ](x : A , xv : B , tl : Tree [A , B ], tr : Tree [A , B ]) =
1127
+ private [this ] def balance [A , B ](tree : Tree [ A , B ] , tl : Tree [A , B ], tr : Tree [A , B ]): Tree [ A , B ] =
1080
1128
if (isRedTree(tl)) {
1081
- if (isRedTree(tr)) RedTree (x, xv, tl.black, tr.black)
1082
- else if (isRedTree(tl.left)) RedTree (tl.key, tl.value, tl.left.black, BlackTree (x, xv, tl.right, tr))
1083
- else if (isRedTree(tl.right))
1084
- RedTree (tl.right.key, tl.right.value, BlackTree (tl.key, tl.value, tl.left, tl.right.left), BlackTree (x, xv, tl.right.right, tr))
1085
- else BlackTree (x, xv, tl, tr)
1129
+ if (isRedTree(tr)) tree.redWithLeftRight(tl.black, tr.black)
1130
+ else if (isRedTree(tl.left)) tl.withLeftRight(tl.left.black, tree.blackWithLeftRight(tl.right, tr))
1131
+ else if (isRedTree(tl.right)) tl.right.withLeftRight(tl.blackWithRight(tl.right.left), tree.blackWithLeftRight(tl.right.right, tr))
1132
+ else tree.blackWithLeftRight(tl, tr)
1086
1133
} else if (isRedTree(tr)) {
1087
- if (isRedTree(tr.right)) RedTree (tr.key, tr.value, BlackTree (x, xv, tl, tr.left), tr.right.black)
1088
- else if (isRedTree(tr.left))
1089
- RedTree (tr.left.key, tr.left.value, BlackTree (x, xv, tl, tr.left.left), BlackTree (tr.key, tr.value, tr.left.right, tr.right))
1090
- else BlackTree (x, xv, tl, tr)
1091
- } else BlackTree (x, xv, tl, tr)
1092
-
1093
- private [this ] def balLeft [A , B ](x : A , xv : B , tl : Tree [A , B ], tr : Tree [A , B ]) =
1094
- if (isRedTree(tl)) RedTree (x, xv, tl.black, tr)
1095
- else if (isBlackTree(tr)) balance(x, xv, tl, tr.red)
1134
+ if (isRedTree(tr.right)) tr.withLeftRight(tree.blackWithLeftRight(tl, tr.left), tr.right.black)
1135
+ else if (isRedTree(tr.left)) tr.left.withLeftRight(tree.blackWithLeftRight(tl, tr.left.left), tr.blackWithLeftRight(tr.left.right, tr.right))
1136
+ else tree.blackWithLeftRight(tl, tr)
1137
+ } else tree.blackWithLeftRight(tl, tr)
1138
+
1139
+ private [this ] def balLeft [A , B ](tree : Tree [A ,B ], tl : Tree [A , B ], tr : Tree [A , B ]): Tree [A , B ] =
1140
+ if (isRedTree(tl)) tree.redWithLeftRight(tl.black, tr)
1141
+ else if (isBlackTree(tr)) balance(tree, tl, tr.red)
1096
1142
else if (isRedTree(tr) && isBlackTree(tr.left))
1097
- RedTree (tr.left.key, tr.left.value, BlackTree (x, xv, tl, tr.left.left), balance(tr.key, tr.value , tr.left.right, tr.right.red))
1143
+ tr.left.redWithLeftRight(tree.blackWithLeftRight( tl, tr.left.left), balance(tr, tr.left.right, tr.right.red))
1098
1144
else sys.error(" Defect: invariance violation" )
1099
1145
1100
- private [this ] def balRight [A , B ](x : A , xv : B , tl : Tree [A , B ], tr : Tree [A , B ]) =
1101
- if (isRedTree(tr)) RedTree (x, xv, tl, tr.black)
1102
- else if (isBlackTree(tl)) balance(x, xv , tl.red, tr)
1146
+ private [this ] def balRight [A , B ](tree : Tree [ A , B ] , tl : Tree [A , B ], tr : Tree [A , B ]): Tree [ A , B ] =
1147
+ if (isRedTree(tr)) tree.redWithLeftRight( tl, tr.black)
1148
+ else if (isBlackTree(tl)) balance(tree , tl.red, tr)
1103
1149
else if (isRedTree(tl) && isBlackTree(tl.right))
1104
- RedTree (tl.right.key, tl.right.value, balance(tl.key , tl.value, tl. left.red, tl.right.left), BlackTree (x, xv, tl.right.right, tr))
1150
+ tl.right.redWithLeftRight( balance(tl, tl.left.red, tl.right.left), tree.blackWithLeftRight( tl.right.right, tr))
1105
1151
else sys.error(" Defect: invariance violation" )
1106
1152
1107
1153
/** `append` is similar to `join2` but requires that both subtrees have the same black height */
1108
- private [this ] def append [A , B ](tl : Tree [A , B ], tr : Tree [A , B ]): Tree [A , B ] =
1154
+ private [this ] def append [A , B ](tl : Tree [A , B ], tr : Tree [A , B ]): Tree [A , B ] = {
1109
1155
if (tl eq null ) tr
1110
1156
else if (tr eq null ) tl
1111
- else if (isRedTree(tl) && isRedTree(tr)) {
1112
- val bc = append(tl.right, tr.left)
1113
- if (isRedTree(bc)) {
1114
- RedTree (bc.key, bc.value, RedTree (tl.key, tl.value, tl.left, bc.left), RedTree (tr.key, tr.value, bc.right, tr.right))
1115
- } else {
1116
- RedTree (tl.key, tl.value, tl.left, RedTree (tr.key, tr.value, bc, tr.right))
1117
- }
1118
- } else if (isBlackTree(tl) && isBlackTree(tr)) {
1119
- val bc = append(tl.right, tr.left)
1120
- if (isRedTree(bc)) {
1121
- RedTree (bc.key, bc.value, BlackTree (tl.key, tl.value, tl.left, bc.left), BlackTree (tr.key, tr.value, bc.right, tr.right))
1122
- } else {
1123
- balLeft(tl.key, tl.value, tl.left, BlackTree (tr.key, tr.value, bc, tr.right))
1124
- }
1125
- } else if (isRedTree(tr)) RedTree (tr.key, tr.value, append(tl, tr.left), tr.right)
1126
- else if (isRedTree(tl)) RedTree (tl.key, tl.value, tl.left, append(tl.right, tr))
1127
- else sys.error(" unmatched tree on append: " + tl + " , " + tr)
1157
+ else if (tl.isRed) {
1158
+ if (tr.isRed) {
1159
+ // tl is red, tr is red
1160
+ val bc = append(tl.right, tr.left)
1161
+ if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right))
1162
+ else tl.withRight(tr.withLeft(bc))
1163
+ } else {
1164
+ // tl is red, tr is black
1165
+ tl.withRight(append(tl.right, tr))
1166
+ }
1167
+ } else {
1168
+ if (tr.isBlack) {
1169
+ // tl is black tr is black
1170
+ val bc = append(tl.right, tr.left)
1171
+ if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right))
1172
+ else balLeft(tl, tl.left, tr.withLeft(bc))
1173
+ } else {
1174
+ // tl is black tr is red
1175
+ tr.withLeft(append(tl, tr.left))
1176
+ }
1177
+ }
1178
+ }
1128
1179
1129
1180
1130
1181
// Bulk operations based on "Just Join for Parallel Ordered Sets" (https://www.cs.cmu.edu/~guyb/papers/BFS16.pdf)
@@ -1142,7 +1193,7 @@ private[collection] object NewRedBlackTree {
1142
1193
/** Compute the rank from a tree and its black height */
1143
1194
@ `inline` private [this ] def rank (t : Tree [_, _], bh : Int ): Int = {
1144
1195
if (t eq null ) 0
1145
- else if (isBlackTree(t) ) 2 * (bh- 1 )
1196
+ else if (t.isBlack ) 2 * (bh- 1 )
1146
1197
else 2 * bh- 1
1147
1198
}
1148
1199
@@ -1178,7 +1229,7 @@ private[collection] object NewRedBlackTree {
1178
1229
1179
1230
private [this ] def join [A , B ](tl : Tree [A , B ], k : A , v : B , tr : Tree [A , B ]): Tree [A , B ] = {
1180
1231
@ tailrec def h (t : Tree [_, _], i : Int ): Int =
1181
- if (t eq null ) i+ 1 else h(t.left, if (isBlackTree(t) ) i+ 1 else i)
1232
+ if (t eq null ) i+ 1 else h(t.left, if (t.isBlack ) i+ 1 else i)
1182
1233
val bhtl = h(tl, 0 )
1183
1234
val bhtr = h(tr, 0 )
1184
1235
if (bhtl > bhtr) {
0 commit comments