Skip to content

Commit 6d17c23

Browse files
committed
Fix (some of?) the crashes that occur if you delete the leftmost, rightmost, or rootmost nodes. I'm the guy who tests his code. You must be the other guy. Addresses #1405
1 parent 87563a3 commit 6d17c23

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

src/edu/stanford/nlp/util/IntervalTree.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class IntervalTree<E extends Comparable<E>, T extends HasInterval<E>> ext
1818
private static final boolean debug = false;
1919

2020
private TreeNode<E,T> root = new TreeNode<>();
21+
TreeNode<E, T> root() { return root; }
2122

2223
// Tree node
2324
public static class TreeNode<E extends Comparable<E>, T extends HasInterval<E>> {
@@ -40,6 +41,10 @@ public void clear() {
4041
right = null;
4142
// parent = null;
4243
}
44+
45+
public String toString() {
46+
return "TreeNode(value=" + value + ", size=" + size + ", maxEnd=" + maxEnd + ")";
47+
}
4348
}
4449

4550
@Override
@@ -237,8 +242,9 @@ public boolean remove(TreeNode<E,T> node, T target)
237242
node.value = node.left.value;
238243
node.size = node.left.size;
239244
node.maxEnd = node.left.maxEnd;
240-
node.left = node.left.left;
245+
// Don't overwrite the left child before getting all of its values!
241246
node.right = node.left.right;
247+
node.left = node.left.left;
242248
if (node.left != null) node.left.parent = node;
243249
if (node.right != null) node.right.parent = node;
244250
} else {
@@ -270,7 +276,18 @@ public boolean remove(TreeNode<E,T> node, T target)
270276
}
271277
boolean res = remove(node.left, target);
272278
if (res) {
273-
node.maxEnd = Interval.max(node.maxEnd, node.left.maxEnd);
279+
node.maxEnd = node.value.getInterval().getEnd();
280+
if (node.right != null) {
281+
node.maxEnd = Interval.max(node.maxEnd, node.right.maxEnd);
282+
}
283+
if (node.left != null) {
284+
if (node.left.size == 0) {
285+
// got called clear() in a pathway which could have been left or right
286+
node.left = null;
287+
} else {
288+
node.maxEnd = Interval.max(node.maxEnd, node.left.maxEnd);
289+
}
290+
}
274291
node.size--;
275292
}
276293
return res;
@@ -281,7 +298,18 @@ public boolean remove(TreeNode<E,T> node, T target)
281298
}
282299
boolean res = remove(node.right, target);
283300
if (res) {
284-
node.maxEnd = Interval.max(node.maxEnd, node.right.maxEnd);
301+
node.maxEnd = node.value.getInterval().getEnd();
302+
if (node.left != null) {
303+
node.maxEnd = Interval.max(node.maxEnd, node.left.maxEnd);
304+
}
305+
if (node.right != null) {
306+
if (node.right.size == 0) {
307+
// got called clear() in a pathway which could have been left or right
308+
node.right = null;
309+
} else {
310+
node.maxEnd = Interval.max(node.maxEnd, node.right.maxEnd);
311+
}
312+
}
285313
node.size--;
286314
}
287315
return res;

test/src/edu/stanford/nlp/util/IntervalTreeTest.java

+72
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,76 @@ public void testIteratorOrdered() throws Exception
160160
}
161161
assertFalse("No more items", iterator.hasNext());
162162
}
163+
164+
public void testSizeOne() {
165+
IntervalTree<Integer, Interval<Integer>> tree = new IntervalTree<>();
166+
tree.add(Interval.toInterval(0, 1));
167+
assertEquals(tree.size(), 1);
168+
tree.remove(Interval.toInterval(0, 1));
169+
assertEquals(tree.size(), 0);
170+
}
171+
172+
public void testSizeTwoDeleteLeft() {
173+
IntervalTree<Integer, Interval<Integer>> tree = new IntervalTree<>();
174+
tree.add(Interval.toInterval(0, 1));
175+
assertEquals(tree.size(), 1);
176+
177+
tree.add(Interval.toInterval(2, 5));
178+
assertEquals(tree.size(), 2);
179+
assertEquals(tree.root().maxEnd.intValue(), 5);
180+
181+
tree.remove(Interval.toInterval(0, 1));
182+
assertEquals(tree.size(), 1);
183+
assertEquals(tree.root().maxEnd.intValue(), 5);
184+
185+
// new tree, insert in opposite order
186+
tree = new IntervalTree<>();
187+
tree.add(Interval.toInterval(2, 5));
188+
assertEquals(tree.size(), 1);
189+
assertEquals(tree.root().maxEnd.intValue(), 5);
190+
191+
tree.add(Interval.toInterval(0, 1));
192+
assertEquals(tree.size(), 2);
193+
assertEquals(tree.root().maxEnd.intValue(), 5);
194+
195+
tree.remove(Interval.toInterval(0, 1));
196+
assertEquals(tree.size(), 1);
197+
assertEquals(tree.root().maxEnd.intValue(), 5);
198+
}
199+
200+
public void testSizeTwoDeleteRight() {
201+
IntervalTree<Integer, Interval<Integer>> tree = new IntervalTree<>();
202+
tree.add(Interval.toInterval(0, 1));
203+
assertEquals(tree.size(), 1);
204+
assertEquals(tree.root().maxEnd.intValue(), 1);
205+
206+
tree.add(Interval.toInterval(2, 5));
207+
assertEquals(tree.size(), 2);
208+
assertEquals(tree.root().maxEnd.intValue(), 5);
209+
210+
tree.remove(Interval.toInterval(2, 5));
211+
assertEquals(tree.size(), 1);
212+
assertEquals(tree.root().maxEnd.intValue(), 1);
213+
214+
tree.remove(Interval.toInterval(0, 1));
215+
assertEquals(tree.size(), 0);
216+
217+
// new tree, insert in opposite order
218+
tree = new IntervalTree<>();
219+
tree.add(Interval.toInterval(2, 5));
220+
assertEquals(tree.size(), 1);
221+
assertEquals(tree.root().maxEnd.intValue(), 5);
222+
223+
tree.add(Interval.toInterval(0, 1));
224+
assertEquals(tree.size(), 2);
225+
assertEquals(tree.root().maxEnd.intValue(), 5);
226+
227+
tree.remove(Interval.toInterval(2, 5));
228+
assertEquals(tree.size(), 1);
229+
assertEquals(tree.root().maxEnd.intValue(), 1);
230+
231+
tree.remove(Interval.toInterval(0, 1));
232+
assertEquals(tree.size(), 0);
233+
234+
}
163235
}

0 commit comments

Comments
 (0)