Skip to content

Commit 9f819b6

Browse files
Merge pull request #118 from Workiva/remove_duplicate_values
Remove duplicate values
2 parents 2d75b8d + 7e6c0ef commit 9f819b6

File tree

5 files changed

+20
-356
lines changed

5 files changed

+20
-356
lines changed

augmentedtree/atree.go

+13-117
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ limitations under the License.
1616

1717
package augmentedtree
1818

19-
import "math"
20-
2119
func intervalOverlaps(n *node, low, high int64, interval Interval, maxDimension uint64) bool {
22-
if !overlaps(n.high, high, n.low, low) {
20+
if !overlaps(n.interval.HighAtDimension(1), high, n.interval.LowAtDimension(1), low) {
2321
return false
2422
}
2523

@@ -55,11 +53,11 @@ func compare(nodeLow, ivLow int64, nodeID, ivID uint64) int {
5553
}
5654

5755
type node struct {
58-
interval Interval
59-
low, high, max, min int64 // max value held by children
60-
children [2]*node // array to hold left/right
61-
red bool // indicates if this node is red
62-
id uint64 // we store the id locally to reduce the number of calls to the method on the interface
56+
interval Interval
57+
max, min int64 // max value held by children
58+
children [2]*node // array to hold left/right
59+
red bool // indicates if this node is red
60+
id uint64 // we store the id locally to reduce the number of calls to the method on the interface
6361
}
6462

6563
func (n *node) query(low, high int64, interval Interval, maxDimension uint64, fn func(node *node)) {
@@ -107,8 +105,6 @@ func newNode(interval Interval, min, max int64, dimension uint64) *node {
107105
}
108106
if interval != nil {
109107
itn.id = interval.ID()
110-
itn.low = interval.LowAtDimension(dimension)
111-
itn.high = interval.HighAtDimension(dimension)
112108
}
113109

114110
return itn
@@ -192,7 +188,7 @@ func (tree *tree) add(iv Interval) {
192188

193189
last = dir
194190
otherLast = takeOpposite(last)
195-
dir = compare(node.low, ivLow, node.id, id)
191+
dir = compare(node.interval.LowAtDimension(1), ivLow, node.id, id)
196192

197193
if grandParent != nil {
198194
helper = grandParent
@@ -235,7 +231,7 @@ func (tree *tree) delete(iv Interval) {
235231

236232
grandParent, parent, node = parent, node, node.children[dir]
237233

238-
dir = compare(node.low, ivLow, node.id, id)
234+
dir = compare(node.interval.LowAtDimension(1), ivLow, node.id, id)
239235
otherDir = takeOpposite(dir)
240236

241237
if node.id == id {
@@ -279,7 +275,7 @@ func (tree *tree) delete(iv Interval) {
279275

280276
if found != nil {
281277
tree.number--
282-
found.interval, found.max, found.min, found.low, found.high, found.id = node.interval, node.max, node.min, node.low, node.high, node.id
278+
found.interval, found.max, found.min, found.id = node.interval, node.max, node.min, node.id
283279
parentDir := intFromBool(parent.children[1] == node)
284280
childDir := intFromBool(node.children[0] == nil)
285281

@@ -292,97 +288,6 @@ func (tree *tree) delete(iv Interval) {
292288
}
293289
}
294290

295-
// insertInterval returns an int indicating if action needs to be taken
296-
// with the given interval. A 1 returned indicates this interval
297-
// needs to be modified. A -1 indicates that this interval needs to
298-
// be deleted. A 0 indicates this interval requires no action.
299-
func insertInterval(dimension uint64, interval Interval, index, count int64) int {
300-
low, high := interval.LowAtDimension(dimension), interval.HighAtDimension(dimension)
301-
if index > high {
302-
return 0
303-
}
304-
305-
if count > 0 {
306-
return 1
307-
}
308-
309-
if index <= low && low-index+high+count < low {
310-
return -1
311-
}
312-
313-
return 1
314-
}
315-
316-
// Insert will shift intervals in the tree based on the specified
317-
// index and the specified count. Dimension specifies where to
318-
// apply the shift. Returned is a list of intervals impacted and
319-
// list of intervals deleted. Intervals are deleted if the shift
320-
// makes the interval size zero or less, ie, min >= max. These
321-
// intervals are automatically removed from the tree. The tree
322-
// does not alter the ranges on the intervals themselves, the consumer
323-
// is expected to do that.
324-
func (tree *tree) Insert(dimension uint64,
325-
index, count int64) (Intervals, Intervals) {
326-
327-
if tree.root == nil { // nothing to do
328-
return nil, nil
329-
}
330-
331-
modified, deleted := intervalsPool.Get().(Intervals), intervalsPool.Get().(Intervals)
332-
333-
tree.root.query(math.MinInt64, math.MaxInt64, nil, tree.maxDimension, func(n *node) {
334-
if dimension > 1 {
335-
action := insertInterval(dimension, n.interval, index, count)
336-
switch action {
337-
case 1:
338-
modified = append(modified, n.interval)
339-
case -1:
340-
deleted = append(deleted, n.interval)
341-
}
342-
return
343-
}
344-
345-
if n.max < index { // won't change min or max in this case
346-
return
347-
}
348-
349-
needsDeletion := false
350-
351-
if n.low >= index && n.low-index+n.high+count < n.low {
352-
needsDeletion = true
353-
}
354-
355-
n.max += count
356-
if n.min >= index {
357-
n.min += count
358-
}
359-
360-
if n.low > index {
361-
n.low += count
362-
if n.low < index {
363-
n.low = index
364-
}
365-
}
366-
367-
if n.high > index {
368-
n.high += count
369-
if n.high < index {
370-
n.high = index
371-
}
372-
}
373-
374-
if needsDeletion {
375-
deleted = append(deleted, n.interval)
376-
} else {
377-
modified = append(modified, n.interval)
378-
}
379-
})
380-
381-
tree.Delete(deleted...)
382-
383-
return modified, deleted
384-
}
385-
386291
// Delete will remove the provided intervals from this tree.
387292
func (tree *tree) Delete(intervals ...Interval) {
388293
for _, iv := range intervals {
@@ -414,21 +319,12 @@ func (tree *tree) Query(interval Interval) Intervals {
414319
return Intervals
415320
}
416321

417-
func (tree *tree) apply(interval Interval, fn func(*node)) {
418-
if tree.root == nil {
419-
return
420-
}
421-
422-
low, high := interval.LowAtDimension(1), interval.HighAtDimension(1)
423-
tree.root.query(low, high, interval, tree.maxDimension, fn)
424-
}
425-
426322
func isRed(node *node) bool {
427323
return node != nil && node.red
428324
}
429325

430326
func setMax(parent *node) {
431-
parent.max = parent.high
327+
parent.max = parent.interval.HighAtDimension(1)
432328

433329
if parent.children[0] != nil && parent.children[0].max > parent.max {
434330
parent.max = parent.children[0].max
@@ -440,7 +336,7 @@ func setMax(parent *node) {
440336
}
441337

442338
func setMin(parent *node) {
443-
parent.min = parent.low
339+
parent.min = parent.interval.LowAtDimension(1)
444340
if parent.children[0] != nil && parent.children[0].min < parent.min {
445341
parent.min = parent.children[0].min
446342
}
@@ -449,8 +345,8 @@ func setMin(parent *node) {
449345
parent.min = parent.children[1].min
450346
}
451347

452-
if parent.low < parent.min {
453-
parent.min = parent.low
348+
if parent.interval.LowAtDimension(1) < parent.min {
349+
parent.min = parent.interval.LowAtDimension(1)
454350
}
455351
}
456352

augmentedtree/atree_test.go

+4-164
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,18 @@ func checkRedBlack(tb testing.TB, node *node, dimension int) (int64, int64, int6
8282
fn(minR, maxR)
8383

8484
min := min(minL, minR)
85-
if min == -1 && node.min != node.low {
85+
if min == -1 && node.min != node.interval.LowAtDimension(1) {
8686
tb.Errorf(`Min not set correctly, node: %+v`, node)
8787
} else if min != -1 && node.children[0] != nil && node.children[0].min != node.min {
8888
tb.Errorf(`Min not set correctly: node: %+v, child: %+v`, node, node.children[0])
89-
} else if min != -1 && node.children[0] == nil && node.min != node.low {
89+
} else if min != -1 && node.children[0] == nil && node.min != node.interval.LowAtDimension(1) {
9090
tb.Errorf(`Min not set correctly: %+v`, node)
9191
}
9292

9393
max := max(maxL, maxR)
94-
if max == -1 && node.max != node.high {
94+
if max == -1 && node.max != node.interval.HighAtDimension(1) {
9595
tb.Errorf(`Max not set correctly, node: %+v`, node)
96-
} else if max > node.high && max != node.max {
96+
} else if max > node.interval.HighAtDimension(1) && max != node.max {
9797
tb.Errorf(`Max not set correctly, max: %+v, node: %+v`, max, node)
9898
}
9999

@@ -598,155 +598,6 @@ func TestAddDeleteDuplicatesRebalanceRandomOrder(t *testing.T) {
598598
assert.Equal(t, uint64(0), it.Len())
599599
}
600600

601-
func TestInsertSingleAtDimension(t *testing.T) {
602-
tree, ivs := constructSingleDimensionTestTree(3)
603-
604-
modified, deleted := tree.Insert(1, 11, 1)
605-
assert.Len(t, deleted, 0)
606-
assert.Equal(t, ivs[1:], modified)
607-
608-
result := tree.Query(constructSingleDimensionInterval(11, 20, 0))
609-
assert.Equal(t, ivs[1:], result)
610-
checkRedBlack(t, tree.root, 1)
611-
612-
assert.Equal(t, int64(0), tree.root.min)
613-
assert.Equal(t, int64(13), tree.root.max)
614-
}
615-
616-
func TestInsertMultipleAtDimension(t *testing.T) {
617-
tree, ivs := constructSingleDimensionTestTree(3)
618-
619-
modified, deleted := tree.Insert(1, 11, 2)
620-
assert.Len(t, deleted, 0)
621-
assert.Equal(t, ivs[1:], modified)
622-
623-
result := tree.Query(constructSingleDimensionInterval(11, 20, 0))
624-
assert.Equal(t, ivs[1:], result)
625-
checkRedBlack(t, tree.root, 1)
626-
627-
assert.Equal(t, int64(0), tree.root.min)
628-
assert.Equal(t, int64(14), tree.root.max)
629-
}
630-
631-
func TestInsertAtLowestIndex(t *testing.T) {
632-
tree, ivs := constructSingleDimensionTestTree(3)
633-
634-
modified, deleted := tree.Insert(1, -1, 1)
635-
assert.Equal(t, ivs[0:], modified)
636-
assert.Len(t, deleted, 0)
637-
638-
result := tree.Query(constructSingleDimensionInterval(0, 0, 0))
639-
assert.Len(t, result, 0)
640-
641-
result = tree.Query(constructSingleDimensionInterval(1, 4, 0))
642-
assert.Equal(t, ivs, result)
643-
644-
checkRedBlack(t, tree.root, 1)
645-
646-
assert.Equal(t, int64(1), tree.root.min)
647-
assert.Equal(t, int64(13), tree.root.max)
648-
}
649-
650-
func TestDeleteSingleAtDimension(t *testing.T) {
651-
tree, ivs := constructSingleDimensionTestTree(3)
652-
653-
modified, deleted := tree.Insert(1, 11, -1)
654-
assert.Equal(t, ivs[1:], modified)
655-
assert.Len(t, deleted, 0)
656-
657-
result := tree.Query(constructSingleDimensionInterval(11, 20, 0))
658-
assert.Equal(t, ivs[1:], result)
659-
660-
result = tree.Query(constructSingleDimensionInterval(9, 20, 0))
661-
assert.Equal(t, ivs, result)
662-
663-
checkRedBlack(t, tree.root, 1)
664-
665-
assert.Equal(t, int64(0), tree.root.min)
666-
assert.Equal(t, int64(11), tree.root.max)
667-
}
668-
669-
func TestDeleteBelowLowestIndex(t *testing.T) {
670-
tree := newTree(1)
671-
672-
ivs := make(Intervals, 0, 3)
673-
for i := int64(0); i < 3; i++ {
674-
iv := constructSingleDimensionInterval(i+1, i+11, uint64(i))
675-
ivs = append(ivs, iv)
676-
}
677-
678-
tree.Add(ivs...)
679-
680-
modified, deleted := tree.Insert(1, 0, -1)
681-
assert.Equal(t, ivs, modified)
682-
assert.Len(t, deleted, 0)
683-
684-
result := tree.Query(constructSingleDimensionInterval(0, 0, 0))
685-
assert.Equal(t, ivs[:1], result)
686-
687-
result = tree.Query(constructSingleDimensionInterval(0, 10, 0))
688-
assert.Equal(t, ivs, result)
689-
690-
checkRedBlack(t, tree.root, 1)
691-
assert.Equal(t, int64(0), tree.root.min)
692-
assert.Equal(t, int64(12), tree.root.max)
693-
}
694-
695-
func TestInsertDeletesInterval(t *testing.T) {
696-
tree, ivs := constructSingleDimensionTestTree(3)
697-
698-
modified, deleted := tree.Insert(1, 0, -11)
699-
assert.Equal(t, ivs[1:], modified)
700-
assert.Equal(t, ivs[:1], deleted)
701-
702-
result := tree.Query(constructSingleDimensionInterval(3, 10, 0))
703-
assert.Len(t, result, 0)
704-
705-
result = tree.Query(constructSingleDimensionInterval(0, 2, 0))
706-
assert.Equal(t, ivs[1:], result)
707-
708-
checkRedBlack(t, tree.root, 1)
709-
assert.Equal(t, uint64(2), tree.Len())
710-
assert.Equal(t, int64(0), tree.root.min)
711-
assert.Equal(t, int64(1), tree.root.max)
712-
}
713-
714-
func TestDeleteMiddleOfRange(t *testing.T) {
715-
tree, ivs := constructSingleDimensionTestTree(3)
716-
717-
modified, deleted := tree.Insert(1, 5, -10)
718-
assert.Equal(t, ivs, modified)
719-
assert.Len(t, deleted, 0)
720-
721-
checkRedBlack(t, tree.root, 1)
722-
assert.Equal(t, int64(0), tree.root.min)
723-
assert.Equal(t, int64(5), tree.root.max)
724-
}
725-
726-
func BenchmarkInsertPositive(b *testing.B) {
727-
numItems := 1000
728-
729-
tree, _ := constructSingleDimensionTestTree(numItems)
730-
731-
b.ResetTimer()
732-
733-
for i := 0; i < b.N; i++ {
734-
tree.Insert(1, 0, 1)
735-
}
736-
}
737-
738-
func BenchmarkInsertNegative(b *testing.B) {
739-
numItems := 1000
740-
741-
tree, _ := constructSingleDimensionTestTree(numItems)
742-
743-
b.ResetTimer()
744-
745-
for i := 0; i < b.N; i++ {
746-
tree.Insert(1, 0, int64(numItems))
747-
}
748-
}
749-
750601
func TestInsertDuplicateIntervalsToRoot(t *testing.T) {
751602
tree := newTree(1)
752603
iv1 := constructSingleDimensionInterval(0, 10, 1)
@@ -771,14 +622,3 @@ func TestInsertDuplicateIntervalChildren(t *testing.T) {
771622
result := tree.Query(constructSingleDimensionInterval(0, 10, 0))
772623
assert.Contains(t, result, iv1)
773624
}
774-
775-
func TestDeleteAtDimensionalSinglePositionReference(t *testing.T) {
776-
tree := newTree(2)
777-
iv := constructMultiDimensionInterval(
778-
0, &dimension{low: 0, high: 1}, &dimension{low: 4, high: 5},
779-
)
780-
tree.Add(iv)
781-
modified, deleted := tree.Insert(2, 1, -1)
782-
assert.Equal(t, Intervals{iv}, modified)
783-
assert.Len(t, deleted, 0)
784-
}

0 commit comments

Comments
 (0)