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 ;
@@ -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