Split calculateParentRefcount()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ReactorStmtCtx.java
index 7b9bea03e1db2a3ad593266aae4c8d73824be5b7..feebe381a7ce48c1e2b17fa52f212c3d76eefc84 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.Empty;
@@ -34,6 +35,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStatementState;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
@@ -41,6 +43,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
@@ -117,7 +120,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
      * {@link #buildEffective()} instance. If this context is reused, it can be inflated to {@link EffectiveInstances}
      * and also act as a common instance reuse site.
      */
-    private @Nullable E effectiveInstance;
+    private @Nullable Object effectiveInstance;
 
     // Master flag controlling whether this context can yield an effective statement
     // FIXME: investigate the mechanics that are being supported by this, as it would be beneficial if we can get rid
@@ -189,10 +192,10 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     public abstract RootStatementContext<?, ?, ?> getRoot();
 
     @Override
-    public abstract Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
+    public abstract Collection<? extends @NonNull StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
 
     @Override
-    public final @NonNull Registry getBehaviourRegistry() {
+    public final Registry getBehaviourRegistry() {
         return getRoot().getBehaviourRegistryImpl();
     }
 
@@ -237,12 +240,6 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         return QName.create(StmtContextUtils.getRootModuleQName(root), root.getRawArgument());
     }
 
-    @Override
-    @Deprecated(since = "7.0.9", forRemoval = true)
-    public final EffectiveStatement<?, ?> original() {
-        return getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
-    }
-
     //
     // In the next two methods we are looking for an effective statement. If we already have an effective instance,
     // defer to it's implementation of the equivalent search. Otherwise we search our substatement contexts.
@@ -253,17 +250,22 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     @Override
     public final <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgument(
             final @NonNull Class<Z> type) {
-        final E existing = effectiveInstance;
+        final E existing = effectiveInstance();
         return existing != null ? existing.findFirstEffectiveSubstatementArgument(type)
             : findSubstatementArgumentImpl(type);
     }
 
     @Override
     public final boolean hasSubstatement(final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
-        final E existing = effectiveInstance;
+        final E existing = effectiveInstance();
         return existing != null ? existing.findFirstEffectiveSubstatement(type).isPresent() : hasSubstatementImpl(type);
     }
 
+    private E effectiveInstance() {
+        final Object existing = effectiveInstance;
+        return existing != null ? EffectiveInstances.local(existing) : null;
+    }
+
     // Visible due to InferredStatementContext's override. At this point we do not have an effective instance available.
     <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgumentImpl(
             final @NonNull Class<Z> type) {
@@ -292,8 +294,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     }
 
     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
-        return toStringHelper.add("definition", definition()).add("rawArgument", rawArgument())
-            .add("refCount", refString());
+        return toStringHelper.add("definition", definition()).add("argument", argument()).add("refCount", refString());
     }
 
     private String refString() {
@@ -363,9 +364,11 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         QNameModule targetModule);
 
     @Override
-    public final ReactorStmtCtx<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
+    public final ReplicaStatementContext<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
         checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent);
-        return replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+        final var ret = replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+        definition().onStatementAdded(ret);
+        return ret;
     }
 
     abstract @NonNull ReplicaStatementContext<A, D, E> replicaAsChildOf(@NonNull StatementContextBase<?, ?, ?> parent);
@@ -378,17 +381,11 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     @Override
     public final E buildEffective() {
-        final E existing;
-        return (existing = effectiveInstance) != null ? existing : loadEffective();
+        final Object existing;
+        return (existing = effectiveInstance) != null ? EffectiveInstances.local(existing) : loadEffective();
     }
 
     private @NonNull E loadEffective() {
-        // Creating an effective statement does not strictly require a declared instance -- there are statements like
-        // 'input', which are implicitly defined.
-        // Our implementation design makes an invariant assumption that buildDeclared() has been called by the time
-        // we attempt to create effective statement:
-        declared();
-
         final E ret = createEffective();
         effectiveInstance = ret;
         // we have called createEffective(), substatements are no longer guarded by us. Let's see if we can clear up
@@ -401,6 +398,43 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     abstract @NonNull E createEffective();
 
+    /**
+     * Routing of the request to build an effective statement from {@link InferredStatementContext} towards the original
+     * definition site. This is needed to pick the correct instantiation method: for declared statements we will
+     * eventually land in {@link AbstractResumedStatement}, for underclared statements that will be
+     * {@link UndeclaredStmtCtx}.
+     *
+     * @param factory Statement factory
+     * @param ctx Inferred statement context, i.e. where the effective statement is instantiated
+     * @return Built effective stateue
+     */
+    abstract @NonNull E createInferredEffective(@NonNull StatementFactory<A, D, E> factory,
+        @NonNull InferredStatementContext<A, D, E> ctx, Stream<? extends ReactorStmtCtx<?, ?, ?>> declared,
+        Stream<? extends ReactorStmtCtx<?, ?, ?>> effective);
+
+    /**
+     * Attach an effective copy of this statement. This essentially acts as a map, where we make a few assumptions:
+     * <ul>
+     *   <li>{@code copy} and {@code this} statement share {@link #getOriginalCtx()} if it exists</li>
+     *   <li>{@code copy} did not modify any statements relative to {@code this}</li>
+     * </ul>
+     *
+     * @param state effective statement state, acting as a lookup key
+     * @param stmt New copy to append
+     * @return {@code stmt} or a previously-created instances with the same {@code state}
+     */
+    @SuppressWarnings("unchecked")
+    final @NonNull E attachEffectiveCopy(final @NonNull EffectiveStatementState state, final @NonNull E stmt) {
+        final Object local = effectiveInstance;
+        final EffectiveInstances<E> instances;
+        if (local instanceof EffectiveInstances) {
+            instances = (EffectiveInstances<E>) local;
+        } else {
+            effectiveInstance = instances = new EffectiveInstances<>((E) local);
+        }
+        return instances.attachCopy(state, stmt);
+    }
+
     /**
      * Walk this statement's copy history and return the statement closest to original which has not had its effective
      * statements modified. This statement and returned substatement logically have the same set of substatements, hence
@@ -438,14 +472,15 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     //
     //
 
+    // Non-final for ImplicitStmtCtx/InferredStatementContext
     @Override
-    public final boolean isSupportedToBuildEffective() {
+    public boolean isSupportedToBuildEffective() {
         return isSupportedToBuildEffective;
     }
 
     @Override
-    public final void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
-        this.isSupportedToBuildEffective = isSupportedToBuildEffective;
+    public final void setUnsupported() {
+        this.isSupportedToBuildEffective = false;
     }
 
     @Override
@@ -845,15 +880,15 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     private byte calculateParentRefcount() {
         final ReactorStmtCtx<?, ?, ?> parent = getParentContext();
-        if (parent == null) {
-            return PARENTREF_ABSENT;
-        }
+        return parent == null ? PARENTREF_ABSENT : parent.refcountForChild();
+    }
 
+    private byte refcountForChild() {
         // A slight wrinkle here is that our machinery handles only PRESENT -> ABSENT invalidation and we can reach here
         // while inference is still ongoing and hence we may not have a complete picture about existing references. We
         // could therefore end up caching an ABSENT result and then that information becoming stale as a new reference
         // is introduced.
-        if (parent.executionOrder() < ExecutionOrder.EFFECTIVE_MODEL) {
+        if (executionOrder() < ExecutionOrder.EFFECTIVE_MODEL) {
             return PARENTREF_UNKNOWN;
         }
 
@@ -862,9 +897,9 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         // - negative (< REFCOUNT_NONE), meaning parent is in some stage of sweeping, hence it does not have
         //   a reference to us
         // - positive (> REFCOUNT_NONE), meaning parent has an explicit refcount which is holding us down
-        final int refs = parent.refcount;
+        final int refs = refcount;
         if (refs == REFCOUNT_NONE) {
-            return parent.parentRefcount();
+            return parentRefcount();
         }
         return refs < REFCOUNT_NONE ? PARENTREF_ABSENT : PARENTREF_PRESENT;
     }