1313import org .variantsync .diffdetective .variation .tree .VariationNode ;
1414import org .variantsync .functjonal .Cast ;
1515
16- import java .lang .reflect .Array ;
1716import java .util .*;
1817import java .util .function .Function ;
1918import java .util .stream .Stream ;
@@ -52,31 +51,51 @@ public class DiffNode<L extends Label> implements HasNodeType {
5251 private Node featureMapping ;
5352
5453 /**
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 ));
54+ * Bundles all the state that may be different before and after an edit.
55+ * @see at
56+ */
57+ private static class TimeDependentState <L extends Label > {
58+ /**
59+ * The parents {@link DiffNode} before and after the edit.
60+ * This array has to be indexed by {@code Time.ordinal()}
61+ *
62+ * Invariant: Iff {@code getParent(time) != null} then
63+ * {@code getParent(time).getChildOrder(time).contains(this)}.
64+ */
65+ public DiffNode <L > parent ;
66+
67+ /**
68+ * The children before and after the edit.
69+ * This array has to be indexed by {@code Time.ordinal()}
70+ *
71+ * Invariant: Iff {@code getChildOrder(time).contains(child)} then
72+ * {@code child.getParent(time) == this}.
73+ */
74+ public List <DiffNode <L >> children ;
75+
76+ /**
77+ * Cache for before and after projections.
78+ * It stores the projection node at each time so that only one instance of {@link Projection}
79+ * per {@link Time} is ever created. This array has to be indexed by {@code Time.ordinal()}
80+ *
81+ * <p>This field is required to allow identity tests of {@link Projection}s with {@code ==}.
82+ */
83+ public Projection <L > projection ;
84+
85+ public TimeDependentState () {
86+ parent = null ;
87+ children = null ;
88+ children = new ArrayList <>();
89+ projection = null ;
90+ }
91+ }
6292
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 ));
93+ private final TimeDependentState <L > stateBefore = new TimeDependentState <L >();
94+ private final TimeDependentState <L > stateAfter = new TimeDependentState <L >();
7195
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 ));
96+ private TimeDependentState <L > at (Time time ) {
97+ return time .match (stateBefore , stateAfter );
98+ }
8099
81100 /**
82101 * Creates a DiffNode with the given parameters.
@@ -104,9 +123,6 @@ public DiffNode(DiffType diffType, NodeType nodeType,
104123 public DiffNode (DiffType diffType ,
105124 DiffLineNumber fromLines , DiffLineNumber toLines ,
106125 Node featureMapping , VariationLabel <L > label ) {
107- children [BEFORE .ordinal ()] = new ArrayList <>();
108- children [AFTER .ordinal ()] = new ArrayList <>();
109-
110126 this .diffType = diffType ;
111127 this .label = label ;
112128 this .from = fromLines ;
@@ -267,7 +283,7 @@ public void drop(Time time) {
267283 * Returns -1 if the given node is not a child of this node.
268284 */
269285 public int indexOfChild (final DiffNode <L > child , Time time ) {
270- return children [ time . ordinal ()] .indexOf (child );
286+ return at ( time ). children .indexOf (child );
271287 }
272288
273289 /**
@@ -278,8 +294,8 @@ public void insertChild(final DiffNode<L> child, int index, Time time) {
278294 Assert .assertFalse (isChild (child , time ), () ->
279295 "Given child " + child + " already has a " + time + " parent (" + child .getParent (time ) + ")!" );
280296
281- children [ time . ordinal ()] .add (index , child );
282- child .parents [ time . ordinal ()] = this ;
297+ at ( time ). children .add (index , child );
298+ child .at ( time ). parent = this ;
283299 }
284300
285301 /**
@@ -291,8 +307,8 @@ public void addChild(final DiffNode<L> child, Time time) {
291307 Assert .assertFalse (isChild (child , time ), () ->
292308 "Given child " + child + " already has a " + time + " parent (" + child .getParent (time ) + ")!" );
293309
294- children [ time . ordinal ()] .add (child );
295- child .parents [ time . ordinal ()] = this ;
310+ at ( time ). children .add (child );
311+ child .at ( time ). parent = this ;
296312 }
297313
298314 /**
@@ -315,8 +331,8 @@ public void addChildren(final Collection<DiffNode<L>> children, Time time) {
315331 public void removeChild (final DiffNode <L > child , Time time ) {
316332 Assert .assertTrue (isChild (child , time ));
317333
318- child .parents [ time . ordinal ()] = null ;
319- children [ time . ordinal ()] .remove (child );
334+ child .at ( time ). parent = null ;
335+ at ( time ). children .remove (child );
320336 }
321337
322338 /**
@@ -341,12 +357,12 @@ public void removeChildren(final Collection<DiffNode<L>> childrenToRemove) {
341357 * @return All removed children.
342358 */
343359 public List <DiffNode <L >> removeChildren (Time time ) {
344- for (var child : children [ time . ordinal ()] ) {
345- child .parents [ time . ordinal ()] = null ;
360+ for (var child : at ( time ). children ) {
361+ child .at ( time ). parent = null ;
346362 }
347363
348- final List <DiffNode <L >> orphans = children [ time . ordinal ()] ;
349- children [ time . ordinal ()] = new ArrayList <>();
364+ final List <DiffNode <L >> orphans = at ( time ). children ;
365+ at ( time ). children = new ArrayList <>();
350366 return orphans ;
351367 }
352368
@@ -387,10 +403,10 @@ public DiffNode<L> split(Time time) {
387403 getParent (time ).replaceChild (this , other , time );
388404
389405 // 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 ;
406+ if (this .at ( time ). projection != null ) {
407+ other .at ( time ). projection = this .at ( time ). projection ;
408+ this .at ( time ). projection = null ;
409+ other .at ( time ). projection .backingNode = other ;
394410 }
395411
396412 return other ;
@@ -409,11 +425,11 @@ public void replaceChild(DiffNode<L> oldChild, DiffNode<L> newChild, Time time)
409425 Assert .assertNull (newChild .getParent (time ));
410426 Assert .assertTrue (newChild .getDiffType ().existsAtTime (time ));
411427
412- for (ListIterator <DiffNode <L >> it = children [ time . ordinal ()] .listIterator (); it .hasNext (); ) {
428+ for (ListIterator <DiffNode <L >> it = at ( time ). children .listIterator (); it .hasNext (); ) {
413429 if (it .next () == oldChild ) {
414430 it .set (newChild );
415- newChild .parents [ time . ordinal ()] = oldChild .parents [ time . ordinal ()] ;
416- oldChild .parents [ time . ordinal ()] = null ;
431+ newChild .at ( time ). parent = oldChild .at ( time ). parent ;
432+ oldChild .at ( time ). parent = null ;
417433 break ;
418434 }
419435 }
@@ -423,7 +439,7 @@ public void replaceChild(DiffNode<L> oldChild, DiffNode<L> newChild, Time time)
423439 * Returns the parent of this node before or after the edit.
424440 */
425441 public DiffNode <L > getParent (Time time ) {
426- return parents [ time . ordinal ()] ;
442+ return at ( time ). parent ;
427443 }
428444
429445 /**
@@ -503,7 +519,7 @@ public void setFormula(Node featureMapping) {
503519 * Returns the order of the children at {@code time}.
504520 */
505521 public List <DiffNode <L >> getChildOrder (Time time ) {
506- return Collections .unmodifiableList (children [ time . ordinal ()] );
522+ return Collections .unmodifiableList (at ( time ). children );
507523 }
508524
509525 /**
@@ -513,8 +529,8 @@ public List<DiffNode<L>> getChildOrder(Time time) {
513529 */
514530 public Stream <DiffNode <L >> getAllChildrenStream () {
515531 return Stream .concat (
516- children [ BEFORE . ordinal ()] .stream (),
517- children [ AFTER . ordinal ()] .stream ().filter (child -> child .getParent (BEFORE ) != this )
532+ at ( BEFORE ). children .stream (),
533+ at ( AFTER ). children .stream ().filter (child -> child .getParent (BEFORE ) != this )
518534 );
519535 };
520536
@@ -578,7 +594,7 @@ public boolean isChild(DiffNode<L> child, Time time) {
578594 * Returns true iff this node has no children.
579595 */
580596 public boolean isLeaf () {
581- return children [ BEFORE . ordinal ()]. isEmpty () && children [ AFTER . ordinal ()] .isEmpty ();
597+ return at ( BEFORE ). children . isEmpty () && at ( AFTER ). children .isEmpty ();
582598 }
583599
584600 /**
@@ -750,11 +766,11 @@ public void assertConsistency() {
750766 public Projection <L > projection (Time time ) {
751767 Assert .assertTrue (getDiffType ().existsAtTime (time ));
752768
753- if (projections [ time . ordinal ()] == null ) {
754- projections [ time . ordinal ()] = new Projection <>(this , time );
769+ if (at ( time ). projection == null ) {
770+ at ( time ). projection = new Projection <>(this , time );
755771 }
756772
757- return projections [ time . ordinal ()] ;
773+ return at ( time ). projection ;
758774 }
759775
760776 /**
0 commit comments