@@ -19,6 +19,7 @@ import org.modelix.model.persistent.Separators
19
19
import org.modelix.streams.IStream
20
20
import org.modelix.streams.flatten
21
21
import org.modelix.streams.plus
22
+ import kotlin.math.abs
22
23
import kotlin.math.max
23
24
import kotlin.math.min
24
25
import kotlin.time.Duration
@@ -53,6 +54,7 @@ sealed class HistoryIndexNode : IObjectData {
53
54
require(self.data == = this )
54
55
val other = otherObj.data
55
56
require(maxTime < other.minTime)
57
+ require(abs(height - other.height) <= 2 )
56
58
return HistoryIndexRangeNode (
57
59
firstVersion = firstVersion,
58
60
lastVersion = other.lastVersion,
@@ -108,7 +110,7 @@ sealed class HistoryIndexNode : IObjectData {
108
110
}
109
111
}
110
112
111
- fun of (version : Object <CPVersion >): HistoryIndexLeafNode {
113
+ fun of (version : Object <CPVersion >): HistoryIndexNode {
112
114
val time = CLVersion (version).getTimestamp() ? : Instant .Companion .fromEpochMilliseconds(0L )
113
115
return HistoryIndexLeafNode (
114
116
versions = listOf (version.ref),
@@ -124,7 +126,7 @@ sealed class HistoryIndexNode : IObjectData {
124
126
}
125
127
126
128
fun Object<HistoryIndexNode>.merge (otherObj : Object <HistoryIndexNode >): Object <HistoryIndexNode > = data.merge(this , otherObj)
127
- fun Object<HistoryIndexNode>.concat (otherObj : Object <HistoryIndexNode >): Object <HistoryIndexNode > = data.concat(this , otherObj)
129
+ fun Object<HistoryIndexNode>.concatUnbalanced (otherObj : Object <HistoryIndexNode >): Object <HistoryIndexNode > = data.concat(this , otherObj)
128
130
val Object <HistoryIndexLeafNode >.time get() = data.time
129
131
130
132
data class HistoryIndexLeafNode (
@@ -194,8 +196,8 @@ data class HistoryIndexLeafNode(
194
196
return when (other) {
195
197
is HistoryIndexLeafNode -> {
196
198
when {
197
- other.time < time -> otherObj.concat (self)
198
- other.time > time -> self.concat (otherObj)
199
+ other.time < time -> otherObj.concatBalanced (self)
200
+ other.time > time -> self.concatBalanced (otherObj)
199
201
else -> HistoryIndexLeafNode (
200
202
versions = (versions.associateBy { it.getHash() } + other.versions.associateBy { it.getHash() }).values.toList(),
201
203
authors = authors + other.authors,
@@ -283,15 +285,15 @@ data class HistoryIndexRangeNode(
283
285
val range1 = resolvedChild1.data.timeRange
284
286
val range2 = resolvedChild2.data.timeRange
285
287
return when {
286
- other.time < range1.start -> otherObj.concat (resolvedChild1).concat (resolvedChild2)
287
- other.time <= range1.endInclusive -> resolvedChild1.merge(otherObj).concat (resolvedChild2)
288
+ other.time < range1.start -> otherObj.concatBalanced (resolvedChild1).concatBalanced (resolvedChild2)
289
+ other.time <= range1.endInclusive -> resolvedChild1.merge(otherObj).concatBalanced (resolvedChild2)
288
290
other.time < range2.start -> if (resolvedChild1.size <= resolvedChild2.size) {
289
- resolvedChild1.concat (otherObj).concat (resolvedChild2)
291
+ resolvedChild1.concatBalanced (otherObj).concatBalanced (resolvedChild2)
290
292
} else {
291
- resolvedChild1.concat (otherObj.concat (resolvedChild2))
293
+ resolvedChild1.concatBalanced (otherObj.concatBalanced (resolvedChild2))
292
294
}
293
- other.time <= range2.endInclusive -> resolvedChild1.concat (resolvedChild2.merge(otherObj))
294
- else -> resolvedChild1.concat (resolvedChild2.concat (otherObj))
295
+ other.time <= range2.endInclusive -> resolvedChild1.concatBalanced (resolvedChild2.merge(otherObj))
296
+ else -> resolvedChild1.concatBalanced (resolvedChild2.concatBalanced (otherObj))
295
297
}
296
298
}
297
299
is HistoryIndexRangeNode -> {
@@ -303,27 +305,27 @@ data class HistoryIndexRangeNode(
303
305
intersects1 && intersects2 -> {
304
306
resolvedChild1.merge(otherObj).merge(resolvedChild2)
305
307
}
306
- intersects1 -> resolvedChild1.merge(otherObj).concat (resolvedChild2)
307
- intersects2 -> resolvedChild1.concat (resolvedChild2.merge(otherObj))
308
+ intersects1 -> resolvedChild1.merge(otherObj).concatBalanced (resolvedChild2)
309
+ intersects2 -> resolvedChild1.concatBalanced (resolvedChild2.merge(otherObj))
308
310
other.maxTime < range1.start -> {
309
311
if (other.size < resolvedChild2.size) {
310
- otherObj.concat (resolvedChild1).concat (resolvedChild2)
312
+ otherObj.concatBalanced (resolvedChild1).concatBalanced (resolvedChild2)
311
313
} else {
312
- otherObj.concat (self)
314
+ otherObj.concatBalanced (self)
313
315
}
314
316
}
315
317
other.maxTime < range2.start -> {
316
318
if (resolvedChild2.size < resolvedChild1.size) {
317
- resolvedChild1.concat (otherObj.concat (resolvedChild2))
319
+ resolvedChild1.concatBalanced (otherObj.concatBalanced (resolvedChild2))
318
320
} else {
319
- resolvedChild1.concat (otherObj).concat (resolvedChild2)
321
+ resolvedChild1.concatBalanced (otherObj).concatBalanced (resolvedChild2)
320
322
}
321
323
}
322
324
else -> {
323
325
if (other.size < resolvedChild1.size) {
324
- resolvedChild1.concat (resolvedChild2.concat (otherObj))
326
+ resolvedChild1.concatBalanced (resolvedChild2.concatBalanced (otherObj))
325
327
} else {
326
- self.concat (otherObj)
328
+ self.concatBalanced (otherObj)
327
329
}
328
330
}
329
331
}
@@ -394,3 +396,32 @@ fun Long.rangeOfSize(size: Long) = this until (this + size)
394
396
fun LongRange.intersect (other : LongRange ): LongRange {
395
397
return if (this .first > other.first) other.intersect(this ) else other.first.. min(this .last, other.last)
396
398
}
399
+
400
+ fun Object<HistoryIndexNode>.rebalance (otherObj : Object <HistoryIndexNode >): Pair <Object <HistoryIndexNode >, Object<HistoryIndexNode>> {
401
+ if (otherObj.height > height + 1 ) {
402
+ val split1 = (otherObj.data as HistoryIndexRangeNode ).child1.resolveNow()
403
+ val split2 = (otherObj.data as HistoryIndexRangeNode ).child2.resolveNow()
404
+ val rebalanced = this .rebalance(split1)
405
+ if (rebalanced.first.height <= split2.height) {
406
+ return rebalanced.first.concatUnbalanced(rebalanced.second) to split2
407
+ } else {
408
+ return rebalanced.first to rebalanced.second.concatUnbalanced(split2)
409
+ }
410
+ } else if (height > otherObj.height + 1 ) {
411
+ val split1 = (this .data as HistoryIndexRangeNode ).child1.resolveNow()
412
+ val split2 = (this .data as HistoryIndexRangeNode ).child2.resolveNow()
413
+ val rebalanced = split2.rebalance(otherObj)
414
+ if (rebalanced.second.height > split1.height) {
415
+ return split1.concatUnbalanced(rebalanced.first) to rebalanced.second
416
+ } else {
417
+ return split1 to rebalanced.first.concatUnbalanced(rebalanced.second)
418
+ }
419
+ } else {
420
+ return this to otherObj
421
+ }
422
+ }
423
+
424
+ fun Object<HistoryIndexNode>.concatBalanced (otherObj : Object <HistoryIndexNode >): Object <HistoryIndexNode > {
425
+ val rebalanced = this .rebalance(otherObj)
426
+ return rebalanced.first.concatUnbalanced(rebalanced.second)
427
+ }
0 commit comments