Skip to content

Commit 34a15fb

Browse files
Merge pull request #117 from Workiva/inclusive_itree
Make interval tree inclusive.
2 parents 6e7864c + e79c1fc commit 34a15fb

File tree

4 files changed

+54
-32
lines changed

4 files changed

+54
-32
lines changed

augmentedtree/atree.go

+19-15
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func intervalOverlaps(n *node, low, high int64, interval Interval, maxDimension
3737
}
3838

3939
func overlaps(high, otherHigh, low, otherLow int64) bool {
40-
return high > otherLow && low < otherHigh
40+
return high >= otherLow && low <= otherHigh
4141
}
4242

4343
// compare returns an int indicating which direction the node
@@ -298,15 +298,15 @@ func (tree *tree) delete(iv Interval) {
298298
// be deleted. A 0 indicates this interval requires no action.
299299
func insertInterval(dimension uint64, interval Interval, index, count int64) int {
300300
low, high := interval.LowAtDimension(dimension), interval.HighAtDimension(dimension)
301-
if index >= high {
301+
if index > high {
302302
return 0
303303
}
304304

305305
if count > 0 {
306306
return 1
307307
}
308308

309-
if index <= low && count*-1 >= high-index {
309+
if index <= low && low-index+high+count < low {
310310
return -1
311311
}
312312

@@ -342,34 +342,38 @@ func (tree *tree) Insert(dimension uint64,
342342
return
343343
}
344344

345-
if n.max <= index { // won't change min or max in this case
345+
if n.max < index { // won't change min or max in this case
346346
return
347347
}
348348

349+
needsDeletion := false
350+
351+
if n.low >= index && n.low-index+n.high+count < n.low {
352+
needsDeletion = true
353+
}
354+
349355
n.max += count
350356
if n.min >= index {
351357
n.min += count
352358
}
353359

354-
mod := false
355-
if n.high > index {
356-
n.high += count
357-
if n.high < index {
358-
n.high = index
359-
}
360-
mod = true
361-
}
362360
if n.low > index {
363361
n.low += count
364362
if n.low < index {
365363
n.low = index
366364
}
367-
mod = true
368365
}
369366

370-
if n.low >= n.high {
367+
if n.high > index {
368+
n.high += count
369+
if n.high < index {
370+
n.high = index
371+
}
372+
}
373+
374+
if needsDeletion {
371375
deleted = append(deleted, n.interval)
372-
} else if mod {
376+
} else {
373377
modified = append(modified, n.interval)
374378
}
375379
})

augmentedtree/atree_test.go

+15-15
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ func constructSingleDimensionQueryTestTree() (
305305

306306
it := newTree(1)
307307

308-
iv1 := constructSingleDimensionInterval(5, 10, 0)
308+
iv1 := constructSingleDimensionInterval(6, 10, 0)
309309
it.Add(iv1)
310310

311311
iv2 := constructSingleDimensionInterval(4, 5, 1)
@@ -329,7 +329,7 @@ func TestSimpleQuery(t *testing.T) {
329329
func TestRightQuery(t *testing.T) {
330330
it, iv1, _, iv3 := constructSingleDimensionQueryTestTree()
331331

332-
result := it.Query(constructSingleDimensionInterval(5, 8, 0))
332+
result := it.Query(constructSingleDimensionInterval(6, 8, 0))
333333

334334
expected := Intervals{iv1, iv3}
335335
assert.Equal(t, expected, result)
@@ -356,7 +356,7 @@ func TestMatchingQuery(t *testing.T) {
356356
func TestNoMatchLeft(t *testing.T) {
357357
it, _, _, _ := constructSingleDimensionQueryTestTree()
358358

359-
result := it.Query(constructSingleDimensionInterval(1, 4, 0))
359+
result := it.Query(constructSingleDimensionInterval(1, 3, 0))
360360

361361
expected := Intervals{}
362362
assert.Equal(t, expected, result)
@@ -365,7 +365,7 @@ func TestNoMatchLeft(t *testing.T) {
365365
func TestNoMatchRight(t *testing.T) {
366366
it, _, _, _ := constructSingleDimensionQueryTestTree()
367367

368-
result := it.Query(constructSingleDimensionInterval(12, 13, 0))
368+
result := it.Query(constructSingleDimensionInterval(13, 13, 0))
369369

370370
expected := Intervals{}
371371
assert.Equal(t, expected, result)
@@ -601,11 +601,11 @@ func TestAddDeleteDuplicatesRebalanceRandomOrder(t *testing.T) {
601601
func TestInsertSingleAtDimension(t *testing.T) {
602602
tree, ivs := constructSingleDimensionTestTree(3)
603603

604-
modified, deleted := tree.Insert(1, 10, 1)
604+
modified, deleted := tree.Insert(1, 11, 1)
605605
assert.Len(t, deleted, 0)
606606
assert.Equal(t, ivs[1:], modified)
607607

608-
result := tree.Query(constructSingleDimensionInterval(10, 20, 0))
608+
result := tree.Query(constructSingleDimensionInterval(11, 20, 0))
609609
assert.Equal(t, ivs[1:], result)
610610
checkRedBlack(t, tree.root, 1)
611611

@@ -616,7 +616,7 @@ func TestInsertSingleAtDimension(t *testing.T) {
616616
func TestInsertMultipleAtDimension(t *testing.T) {
617617
tree, ivs := constructSingleDimensionTestTree(3)
618618

619-
modified, deleted := tree.Insert(1, 10, 2)
619+
modified, deleted := tree.Insert(1, 11, 2)
620620
assert.Len(t, deleted, 0)
621621
assert.Equal(t, ivs[1:], modified)
622622

@@ -635,7 +635,7 @@ func TestInsertAtLowestIndex(t *testing.T) {
635635
assert.Equal(t, ivs[0:], modified)
636636
assert.Len(t, deleted, 0)
637637

638-
result := tree.Query(constructSingleDimensionInterval(0, 1, 0))
638+
result := tree.Query(constructSingleDimensionInterval(0, 0, 0))
639639
assert.Len(t, result, 0)
640640

641641
result = tree.Query(constructSingleDimensionInterval(1, 4, 0))
@@ -650,12 +650,12 @@ func TestInsertAtLowestIndex(t *testing.T) {
650650
func TestDeleteSingleAtDimension(t *testing.T) {
651651
tree, ivs := constructSingleDimensionTestTree(3)
652652

653-
modified, deleted := tree.Insert(1, 10, -1)
653+
modified, deleted := tree.Insert(1, 11, -1)
654654
assert.Equal(t, ivs[1:], modified)
655655
assert.Len(t, deleted, 0)
656656

657-
result := tree.Query(constructSingleDimensionInterval(10, 20, 0))
658-
assert.Equal(t, ivs[2:], result)
657+
result := tree.Query(constructSingleDimensionInterval(11, 20, 0))
658+
assert.Equal(t, ivs[1:], result)
659659

660660
result = tree.Query(constructSingleDimensionInterval(9, 20, 0))
661661
assert.Equal(t, ivs, result)
@@ -681,7 +681,7 @@ func TestDeleteBelowLowestIndex(t *testing.T) {
681681
assert.Equal(t, ivs, modified)
682682
assert.Len(t, deleted, 0)
683683

684-
result := tree.Query(constructSingleDimensionInterval(0, 1, 0))
684+
result := tree.Query(constructSingleDimensionInterval(0, 0, 0))
685685
assert.Equal(t, ivs[:1], result)
686686

687687
result = tree.Query(constructSingleDimensionInterval(0, 10, 0))
@@ -695,11 +695,11 @@ func TestDeleteBelowLowestIndex(t *testing.T) {
695695
func TestInsertDeletesInterval(t *testing.T) {
696696
tree, ivs := constructSingleDimensionTestTree(3)
697697

698-
modified, deleted := tree.Insert(1, 0, -10)
698+
modified, deleted := tree.Insert(1, 0, -11)
699699
assert.Equal(t, ivs[1:], modified)
700700
assert.Equal(t, ivs[:1], deleted)
701701

702-
result := tree.Query(constructSingleDimensionInterval(2, 10, 0))
702+
result := tree.Query(constructSingleDimensionInterval(3, 10, 0))
703703
assert.Len(t, result, 0)
704704

705705
result = tree.Query(constructSingleDimensionInterval(0, 2, 0))
@@ -708,7 +708,7 @@ func TestInsertDeletesInterval(t *testing.T) {
708708
checkRedBlack(t, tree.root, 1)
709709
assert.Equal(t, uint64(2), tree.Len())
710710
assert.Equal(t, int64(0), tree.root.min)
711-
assert.Equal(t, int64(2), tree.root.max)
711+
assert.Equal(t, int64(1), tree.root.max)
712712
}
713713

714714
func TestDeleteMiddleOfRange(t *testing.T) {

augmentedtree/interface.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ range handling.
3232
package augmentedtree
3333

3434
// Interval is the interface that must be implemented by any
35-
// item added to the interval tree.
35+
// item added to the interval tree. This interface is similar to the
36+
// interval found in the rangetree package and it should be possible
37+
// for the same struct to implement both interfaces. Note that ranges
38+
// here are inclusive.
3639
type Interval interface {
3740
// LowAtDimension returns an integer representing the lower bound
3841
// at the requested dimension.

augmentedtree/multidimensional_test.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,21 @@ func TestAddRebalanceInOrderMultiDimensions(t *testing.T) {
130130
assert.Equal(t, uint64(10), it.Len())
131131
}
132132

133+
func TestInsertAtMax(t *testing.T) {
134+
it := newTree(2)
135+
iv := constructMultiDimensionInterval(0, &dimension{0, 0}, &dimension{0, 0})
136+
137+
it.Add(iv)
138+
139+
modified, deleted := it.Insert(1, 0, 1)
140+
assert.Empty(t, deleted)
141+
assert.Len(t, modified, 1)
142+
143+
modified, deleted = it.Insert(2, 0, 1)
144+
assert.Empty(t, deleted)
145+
assert.Len(t, modified, 1)
146+
}
147+
133148
func TestAddRebalanceReverseOrderMultiDimensions(t *testing.T) {
134149
it := newTree(2)
135150

@@ -482,7 +497,7 @@ func TestInsertPositiveMultipleDimensions(t *testing.T) {
482497
func TestInsertNegativeMultipleDimensions(t *testing.T) {
483498
it, iv1, iv2, iv3 := constructMultiDimensionQueryTestTree()
484499

485-
modified, deleted := it.Insert(2, 4, -1)
500+
modified, deleted := it.Insert(2, 4, -2)
486501
assert.Equal(t, Intervals{iv1, iv3}, modified)
487502
assert.Equal(t, Intervals{iv2}, deleted)
488503

0 commit comments

Comments
 (0)