Return ReactorStmtCtx from ensureCompletedPhase()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.java
index 65656d4efa5ba85c3e4541b6cf033756f4170547..cc902f7c6aa59a5de14b8d91251a5bffad32346e 100644 (file)
@@ -96,22 +96,45 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
 
-    //
-    // {@link CopyHistory} encoded as a single byte. We still have 4 bits unused.
-    //
+    // Bottom 4 bits, encoding a CopyHistory, aight?
+    private static final byte COPY_ORIGINAL              = 0x00;
     private static final byte COPY_LAST_TYPE_MASK        = 0x03;
+    @Deprecated(since = "7.0.9")
     private static final byte COPY_ADDED_BY_USES         = 0x04;
     private static final byte COPY_ADDED_BY_AUGMENTATION = 0x08;
-    private static final byte COPY_ORIGINAL              = 0x00;
 
-    private final byte copyHistory;
+    // Top four bits, of which we define the topmost two to 0. We use the bottom two to encode last CopyType, aight?
+    private static final int COPY_CHILD_TYPE_SHIFT       = 4;
+
+    private static final CopyType @NonNull [] COPY_TYPE_VALUES = CopyType.values();
 
     static {
-        final int copyTypes = CopyType.values().length;
+        final int copyTypes = COPY_TYPE_VALUES.length;
         // This implies CopyType.ordinal() is <= COPY_TYPE_MASK
         verify(copyTypes == COPY_LAST_TYPE_MASK + 1, "Unexpected %s CopyType values", copyTypes);
     }
 
+    /**
+     * 8 bits worth of instance storage. This is treated as a constant bit field with following structure:
+     * <pre>
+     *   <code>
+     * |7|6|5|4|3|2|1|0|
+     * |0 0|cct|a|u|lst|
+     *   </code>
+     * </pre>
+     *
+     * <p>
+     * The four allocated fields are:
+     * <ul>
+     *   <li>{@code lst}, encoding the four states corresponding to {@link CopyHistory#getLastOperation()}</li>
+     *   <li>{@code u}, encoding {@link #isAddedByUses()}</li>
+     *   <li>{@code a}, encoding {@link #isAugmenting()}</li>
+     *   <li>{@code cct} encoding {@link #childCopyType()}</li>
+     * </ul>
+     * We still have two unused bits.
+     */
+    private final byte bitsAight;
+
     // Note: this field can strictly be derived in InferredStatementContext, but it forms the basis of many of our
     //       operations, hence we want to keep it close by.
     private final @NonNull StatementDefinitionContext<A, D, E> definition;
@@ -130,24 +153,26 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     // Copy constructor used by subclasses to implement reparent()
     StatementContextBase(final StatementContextBase<A, D, E> original) {
         super(original);
-        this.copyHistory = original.copyHistory;
+        this.bitsAight = original.bitsAight;
         this.definition = original.definition;
         this.executionOrder = original.executionOrder;
     }
 
     StatementContextBase(final StatementDefinitionContext<A, D, E> def) {
         this.definition = requireNonNull(def);
-        this.copyHistory = COPY_ORIGINAL;
+        this.bitsAight = COPY_ORIGINAL;
     }
 
     StatementContextBase(final StatementDefinitionContext<A, D, E> def, final CopyType copyType) {
         this.definition = requireNonNull(def);
-        this.copyHistory = (byte) copyFlags(copyType);
+        this.bitsAight = (byte) copyFlags(copyType);
     }
 
-    StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType) {
+    StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType,
+            final CopyType childCopyType) {
         this.definition = prototype.definition;
-        this.copyHistory = (byte) (copyFlags(copyType) | prototype.copyHistory & ~COPY_LAST_TYPE_MASK);
+        this.bitsAight = (byte) (copyFlags(copyType)
+            | prototype.bitsAight & ~COPY_LAST_TYPE_MASK | childCopyType.ordinal() << COPY_CHILD_TYPE_SHIFT);
     }
 
     private static int copyFlags(final CopyType copyType) {
@@ -196,18 +221,24 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
+    @Deprecated(since = "7.0.9")
     public final boolean isAddedByUses() {
-        return (copyHistory & COPY_ADDED_BY_USES) != 0;
+        return (bitsAight & COPY_ADDED_BY_USES) != 0;
     }
 
     @Override
     public final boolean isAugmenting() {
-        return (copyHistory & COPY_ADDED_BY_AUGMENTATION) != 0;
+        return (bitsAight & COPY_ADDED_BY_AUGMENTATION) != 0;
     }
 
     @Override
     public final CopyType getLastOperation() {
-        return CopyType.values()[copyHistory & COPY_LAST_TYPE_MASK];
+        return COPY_TYPE_VALUES[bitsAight & COPY_LAST_TYPE_MASK];
+    }
+
+    // This method exists only for space optimization of InferredStatementContext
+    final CopyType childCopyType() {
+        return COPY_TYPE_VALUES[bitsAight >> COPY_CHILD_TYPE_SHIFT & COPY_LAST_TYPE_MASK];
     }
 
     //
@@ -320,10 +351,8 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
             final Mutable<?, ?, ?> substatement) {
-        verifyStatement(substatement);
-
+        final ReactorStmtCtx<?, ?, ?> stmt = verifyStatement(substatement);
         final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, 1);
-        final ReactorStmtCtx<?, ?, ?> stmt = (ReactorStmtCtx<?, ?, ?>) substatement;
         ensureCompletedExecution(stmt);
         resized.add(stmt);
         return resized;
@@ -365,9 +394,10 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     abstract Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete();
 
     // exposed for InferredStatementContext only
-    final void ensureCompletedPhase(final Mutable<?, ?, ?> stmt) {
-        verifyStatement(stmt);
-        ensureCompletedExecution((ReactorStmtCtx<?, ?, ?>) stmt);
+    final ReactorStmtCtx<?, ?, ?> ensureCompletedPhase(final Mutable<?, ?, ?> stmt) {
+        final var ret = verifyStatement(stmt);
+        ensureCompletedExecution(ret);
+        return ret;
     }
 
     // Make sure target statement has transitioned at least to our phase (if we have one). This method is just before we
@@ -383,8 +413,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         verify(stmt.tryToCompletePhase(executionOrder), "Statement %s cannot complete phase %s", stmt, executionOrder);
     }
 
-    private static void verifyStatement(final Mutable<?, ?, ?> stmt) {
+    private static ReactorStmtCtx<?, ?, ?> verifyStatement(final Mutable<?, ?, ?> stmt) {
         verify(stmt instanceof ReactorStmtCtx, "Unexpected statement %s", stmt);
+        return (ReactorStmtCtx<?, ?, ?>) stmt;
     }
 
     private List<ReactorStmtCtx<?, ?, ?>> beforeAddEffectiveStatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
@@ -446,7 +477,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     @Override
     final boolean doTryToCompletePhase(final byte targetOrder) {
-        final boolean finished = phaseMutation.isEmpty() ? true : runMutations(targetOrder);
+        final boolean finished = phaseMutation.isEmpty() || runMutations(targetOrder);
         if (completeChildren(targetOrder) && finished) {
             onPhaseCompleted(targetOrder);
             return true;
@@ -468,7 +499,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     private boolean runMutations(final byte targetOrder) {
         final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(targetOrder));
         final Collection<ContextMutation> openMutations = phaseMutation.get(phase);
-        return openMutations.isEmpty() ? true : runMutations(phase, openMutations);
+        return openMutations.isEmpty() || runMutations(phase, openMutations);
     }
 
     private boolean runMutations(final ModelProcessingPhase phase, final Collection<ContextMutation> openMutations) {
@@ -764,7 +795,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             return null;
         }
 
-        parent.ensureCompletedPhase(copy);
+        parent.ensureCompletedExecution(copy);
         return canReuseCurrent(copy) ? this : copy;
     }
 
@@ -779,8 +810,13 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     public final Mutable<?, ?, ?> childCopyOf(final StmtContext<?, ?, ?> stmt, final CopyType type,
             final QNameModule targetModule) {
         checkEffectiveModelCompleted(stmt);
-        checkArgument(stmt instanceof StatementContextBase, "Unsupported statement %s", stmt);
-        return childCopyOf((StatementContextBase<?, ?, ?>) stmt, type, targetModule);
+        if (stmt instanceof StatementContextBase) {
+            return childCopyOf((StatementContextBase<?, ?, ?>) stmt, type, targetModule);
+        } else if (stmt instanceof ReplicaStatementContext) {
+            return ((ReplicaStatementContext<?, ?, ?>) stmt).replicaAsChildOf(this);
+        } else {
+            throw new IllegalArgumentException("Unsupported statement " + stmt);
+        }
     }
 
     private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
@@ -812,6 +848,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
             copy = new InferredStatementContext<>(result, original, childCopyType, type, targetModule);
             result.addEffectiveSubstatement(copy);
+            result.definition.onStatementAdded(result);
         } else {
             result = copy = new InferredStatementContext<>(this, original, type, type, targetModule);
         }