Skip to content

Commit cf30d24

Browse files
committed
refactor: refactor the time dependent fields in DiffNode
This pattern should be more understandable than the previous array based implementation. Furthermore, it is now much easier to add new time dependent fields.
1 parent 3a778b5 commit cf30d24

1 file changed

Lines changed: 66 additions & 54 deletions

File tree

  • src/main/java/org/variantsync/diffdetective/variation/diff

src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import org.variantsync.diffdetective.variation.tree.VariationNode;
1414
import org.variantsync.functjonal.Cast;
1515

16-
import java.lang.reflect.Array;
1716
import java.util.*;
1817
import java.util.function.Function;
1918
import java.util.stream.Stream;
@@ -51,32 +50,48 @@ public class DiffNode<L extends Label> implements HasNodeType {
5150

5251
private Node featureMapping;
5352

54-
/**
55-
* The parents {@link DiffNode} before and after the edit.
56-
* This array has to be indexed by {@code Time.ordinal()}
57-
*
58-
* Invariant: Iff {@code getParent(time) != null} then
59-
* {@code getParent(time).getChildOrder(time).contains(this)}.
60-
*/
61-
private DiffNode<L>[] parents = Cast.unchecked(Array.newInstance(DiffNode.class, 2));
53+
private static class TimeDependentState<L extends Label> {
54+
/**
55+
* The parents {@link DiffNode} before and after the edit.
56+
* This array has to be indexed by {@code Time.ordinal()}
57+
*
58+
* Invariant: Iff {@code getParent(time) != null} then
59+
* {@code getParent(time).getChildOrder(time).contains(this)}.
60+
*/
61+
public DiffNode<L> parent;
62+
63+
/**
64+
* The children before and after the edit.
65+
* This array has to be indexed by {@code Time.ordinal()}
66+
*
67+
* Invariant: Iff {@code getChildOrder(time).contains(child)} then
68+
* {@code child.getParent(time) == this}.
69+
*/
70+
public List<DiffNode<L>> children;
71+
72+
/**
73+
* Cache for before and after projections.
74+
* It stores the projection node at each time so that only one instance of {@link Projection}
75+
* per {@link Time} is ever created. This array has to be indexed by {@code Time.ordinal()}
76+
*
77+
* <p>This field is required to allow identity tests of {@link Projection}s with {@code ==}.
78+
*/
79+
public Projection<L> projection;
80+
81+
public TimeDependentState() {
82+
parent = null;
83+
children = null;
84+
children = new ArrayList<>();
85+
projection = null;
86+
}
87+
}
6288

63-
/**
64-
* The children before and after the edit.
65-
* This array has to be indexed by {@code Time.ordinal()}
66-
*
67-
* Invariant: Iff {@code getChildOrder(time).contains(child)} then
68-
* {@code child.getParent(time) == this}.
69-
*/
70-
private final List<DiffNode<L>>[] children = Cast.unchecked(Array.newInstance(List.class, 2));
89+
private final TimeDependentState<L> stateBefore = new TimeDependentState<L>();
90+
private final TimeDependentState<L> stateAfter = new TimeDependentState<L>();
7191

72-
/**
73-
* Cache for before and after projections.
74-
* It stores the projection node at each time so that only one instance of {@link Projection}
75-
* per {@link Time} is ever created. This array has to be indexed by {@code Time.ordinal()}
76-
*
77-
* <p>This field is required to allow identity tests of {@link Projection}s with {@code ==}.
78-
*/
79-
private Projection<L>[] projections = Cast.unchecked(Array.newInstance(Projection.class, 2));
92+
private TimeDependentState<L> at(Time time) {
93+
return time.match(stateBefore, stateAfter);
94+
}
8095

8196
/**
8297
* Creates a DiffNode with the given parameters.
@@ -104,9 +119,6 @@ public DiffNode(DiffType diffType, NodeType nodeType,
104119
public DiffNode(DiffType diffType,
105120
DiffLineNumber fromLines, DiffLineNumber toLines,
106121
Node featureMapping, VariationLabel<L> label) {
107-
children[BEFORE.ordinal()] = new ArrayList<>();
108-
children[AFTER.ordinal()] = new ArrayList<>();
109-
110122
this.diffType = diffType;
111123
this.label = label;
112124
this.from = fromLines;
@@ -267,7 +279,7 @@ public void drop(Time time) {
267279
* Returns -1 if the given node is not a child of this node.
268280
*/
269281
public int indexOfChild(final DiffNode<L> child, Time time) {
270-
return children[time.ordinal()].indexOf(child);
282+
return at(time).children.indexOf(child);
271283
}
272284

273285
/**
@@ -278,8 +290,8 @@ public void insertChild(final DiffNode<L> child, int index, Time time) {
278290
Assert.assertFalse(isChild(child, time), () ->
279291
"Given child " + child + " already has a " + time + " parent (" + child.getParent(time) + ")!");
280292

281-
children[time.ordinal()].add(index, child);
282-
child.parents[time.ordinal()] = this;
293+
at(time).children.add(index, child);
294+
child.at(time).parent = this;
283295
}
284296

285297
/**
@@ -291,8 +303,8 @@ public void addChild(final DiffNode<L> child, Time time) {
291303
Assert.assertFalse(isChild(child, time), () ->
292304
"Given child " + child + " already has a " + time + " parent (" + child.getParent(time) + ")!");
293305

294-
children[time.ordinal()].add(child);
295-
child.parents[time.ordinal()] = this;
306+
at(time).children.add(child);
307+
child.at(time).parent = this;
296308
}
297309

298310
/**
@@ -315,8 +327,8 @@ public void addChildren(final Collection<DiffNode<L>> children, Time time) {
315327
public void removeChild(final DiffNode<L> child, Time time) {
316328
Assert.assertTrue(isChild(child, time));
317329

318-
child.parents[time.ordinal()] = null;
319-
children[time.ordinal()].remove(child);
330+
child.at(time).parent = null;
331+
at(time).children.remove(child);
320332
}
321333

322334
/**
@@ -341,12 +353,12 @@ public void removeChildren(final Collection<DiffNode<L>> childrenToRemove) {
341353
* @return All removed children.
342354
*/
343355
public List<DiffNode<L>> removeChildren(Time time) {
344-
for (var child : children[time.ordinal()]) {
345-
child.parents[time.ordinal()] = null;
356+
for (var child : at(time).children) {
357+
child.at(time).parent = null;
346358
}
347359

348-
final List<DiffNode<L>> orphans = children[time.ordinal()];
349-
children[time.ordinal()] = new ArrayList<>();
360+
final List<DiffNode<L>> orphans = at(time).children;
361+
at(time).children = new ArrayList<>();
350362
return orphans;
351363
}
352364

@@ -387,10 +399,10 @@ public DiffNode<L> split(Time time) {
387399
getParent(time).replaceChild(this, other, time);
388400

389401
// Preserve the projection by changing its `backingNode` to `other`.
390-
if (this.projections[time.ordinal()] != null) {
391-
other.projections[time.ordinal()] = this.projections[time.ordinal()];
392-
this.projections[time.ordinal()] = null;
393-
other.projections[time.ordinal()].backingNode = other;
402+
if (this.at(time).projection != null) {
403+
other.at(time).projection = this.at(time).projection;
404+
this.at(time).projection = null;
405+
other.at(time).projection.backingNode = other;
394406
}
395407

396408
return other;
@@ -409,11 +421,11 @@ public void replaceChild(DiffNode<L> oldChild, DiffNode<L> newChild, Time time)
409421
Assert.assertNull(newChild.getParent(time));
410422
Assert.assertTrue(newChild.getDiffType().existsAtTime(time));
411423

412-
for (ListIterator<DiffNode<L>> it = children[time.ordinal()].listIterator(); it.hasNext(); ) {
424+
for (ListIterator<DiffNode<L>> it = at(time).children.listIterator(); it.hasNext(); ) {
413425
if (it.next() == oldChild) {
414426
it.set(newChild);
415-
newChild.parents[time.ordinal()] = oldChild.parents[time.ordinal()];
416-
oldChild.parents[time.ordinal()] = null;
427+
newChild.at(time).parent = oldChild.at(time).parent;
428+
oldChild.at(time).parent = null;
417429
break;
418430
}
419431
}
@@ -423,7 +435,7 @@ public void replaceChild(DiffNode<L> oldChild, DiffNode<L> newChild, Time time)
423435
* Returns the parent of this node before or after the edit.
424436
*/
425437
public DiffNode<L> getParent(Time time) {
426-
return parents[time.ordinal()];
438+
return at(time).parent;
427439
}
428440

429441
/**
@@ -503,7 +515,7 @@ public void setFormula(Node featureMapping) {
503515
* Returns the order of the children at {@code time}.
504516
*/
505517
public List<DiffNode<L>> getChildOrder(Time time) {
506-
return Collections.unmodifiableList(children[time.ordinal()]);
518+
return Collections.unmodifiableList(at(time).children);
507519
}
508520

509521
/**
@@ -513,8 +525,8 @@ public List<DiffNode<L>> getChildOrder(Time time) {
513525
*/
514526
public Stream<DiffNode<L>> getAllChildrenStream() {
515527
return Stream.concat(
516-
children[BEFORE.ordinal()].stream(),
517-
children[AFTER.ordinal()].stream().filter(child -> child.getParent(BEFORE) != this)
528+
at(BEFORE).children.stream(),
529+
at(AFTER).children.stream().filter(child -> child.getParent(BEFORE) != this)
518530
);
519531
};
520532

@@ -578,7 +590,7 @@ public boolean isChild(DiffNode<L> child, Time time) {
578590
* Returns true iff this node has no children.
579591
*/
580592
public boolean isLeaf() {
581-
return children[BEFORE.ordinal()].isEmpty() && children[AFTER.ordinal()].isEmpty();
593+
return at(BEFORE).children.isEmpty() && at(AFTER).children.isEmpty();
582594
}
583595

584596
/**
@@ -750,11 +762,11 @@ public void assertConsistency() {
750762
public Projection<L> projection(Time time) {
751763
Assert.assertTrue(getDiffType().existsAtTime(time));
752764

753-
if (projections[time.ordinal()] == null) {
754-
projections[time.ordinal()] = new Projection<>(this, time);
765+
if (at(time).projection == null) {
766+
at(time).projection = new Projection<>(this, time);
755767
}
756768

757-
return projections[time.ordinal()];
769+
return at(time).projection;
758770
}
759771

760772
/**

0 commit comments

Comments
 (0)