import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
-import com.google.common.annotations.Beta;
-import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport.CopyPolicy;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.UndeclaredStatementFactory;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener;
import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.PredicateValueAddedListener;
* @param <D> Declared Statement representation
* @param <E> Effective Statement representation
*/
-public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
extends ReactorStmtCtx<A, D, E> implements CopyHistory {
/**
* Event listener when an item is added to model namespace.
// 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")
+ @Deprecated(since = "7.0.9", forRemoval = true)
private static final byte COPY_ADDED_BY_USES = 0x04;
private static final byte COPY_ADDED_BY_AUGMENTATION = 0x08;
// 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);
}
*/
private byte executionOrder;
+ // TODO: we a single byte of alignment shadow left, we should think how we can use it to cache information we build
+ // during InferredStatementContext.tryToReusePrototype(). We usually end up being routed to
+ // copyAsChildOfImpl() -- which performs an eager instantiation and checks for changes afterwards. We should
+ // be able to capture how parent scope affects the copy in a few bits. If we can do that, than we can reap
+ // the benefits by just examining new parent context and old parent context contribution to the state. If
+ // their impact is the same, we can skip instantiation of statements and directly reuse them (individually,
+ // or as a complete file).
+ //
+ // Whatever we end up tracking, we need to track two views of that -- for the statement itself
+ // (sans substatements) and a summary of substatements. I think it should be possible to get this working
+ // with 2x5bits -- we have up to 15 mutable bits available if we share the field with implicitDeclaredFlag.
+
// Copy constructor used by subclasses to implement reparent()
StatementContextBase(final StatementContextBase<A, D, E> original) {
super(original);
}
private static byte historyFlags(final CopyType copyType) {
- switch (copyType) {
- case ADDED_BY_AUGMENTATION:
- return COPY_ADDED_BY_AUGMENTATION;
- case ADDED_BY_USES:
- return COPY_ADDED_BY_USES;
- case ADDED_BY_USES_AUGMENTATION:
- return COPY_ADDED_BY_AUGMENTATION | COPY_ADDED_BY_USES;
- case ORIGINAL:
- return COPY_ORIGINAL;
- default:
- throw new VerifyException("Unhandled type " + copyType);
- }
+ return switch (copyType) {
+ case ADDED_BY_AUGMENTATION -> COPY_ADDED_BY_AUGMENTATION;
+ case ADDED_BY_USES -> COPY_ADDED_BY_USES;
+ case ADDED_BY_USES_AUGMENTATION -> COPY_ADDED_BY_AUGMENTATION | COPY_ADDED_BY_USES;
+ case ORIGINAL -> COPY_ORIGINAL;
+ };
}
@Override
- public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
+ public final Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
return effectOfStatement;
}
@Override
- public void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
+ public final void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
if (ctxs.isEmpty()) {
return;
}
}
@Override
- @Deprecated(since = "7.0.9")
+ @Deprecated(since = "7.0.9", forRemoval = true)
public final boolean isAddedByUses() {
return (bitsAight & COPY_ADDED_BY_USES) != 0;
}
@Override
+ @Deprecated(since = "8.0.0")
public final boolean isAugmenting() {
return (bitsAight & COPY_ADDED_BY_AUGMENTATION) != 0;
}
@Override
public final CopyType getLastOperation() {
- return CopyType.values()[bitsAight & 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 CopyType.values()[bitsAight >> COPY_CHILD_TYPE_SHIFT & COPY_LAST_TYPE_MASK];
+ return COPY_TYPE_VALUES[bitsAight >> COPY_CHILD_TYPE_SHIFT & COPY_LAST_TYPE_MASK];
}
//
return effective.isEmpty() ? ImmutableList.of() : effective;
}
- public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef);
-
static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef) {
if (effective.isEmpty()) {
return shrinkEffective(effective);
}
- /**
- * Removes a statement context from the effective substatements based on its statement definition (i.e statement
- * keyword) and raw (in String form) statement argument. The statement context is removed only if both statement
- * definition and statement argument match with one of the effective substatements' statement definition
- * and argument.
- *
- * <p>
- * If the statementArg parameter is null, the statement context is removed based only on its statement definition.
- *
- * @param statementDef statement definition of the statement context to remove
- * @param statementArg statement argument of the statement context to remove
- */
- public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef,
- String statementArg);
-
static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef,
final String statementArg) {
return shrinkEffective(effective);
}
- // YANG example: RPC/action statements always have 'input' and 'output' defined
- @Beta
- public <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> @NonNull Mutable<X, Y, Z>
- appendImplicitSubstatement(final StatementSupport<X, Y, Z> support, final String rawArg) {
- // FIXME: YANGTOOLS-652: This does not need to be a SubstatementContext, in can be a specialized
- // StatementContextBase subclass.
- final Mutable<X, Y, Z> ret = new SubstatementContext<>(this, new StatementDefinitionContext<>(support),
- ImplicitSubstatement.of(sourceReference()), rawArg);
+ @Override
+ public final <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
+ Mutable<X, Y, Z> createUndeclaredSubstatement(final StatementSupport<X, Y, Z> support, final X arg) {
+ requireNonNull(support);
+ checkArgument(support instanceof UndeclaredStatementFactory, "Unsupported statement support %s", support);
+
+ final var ret = new UndeclaredStmtCtx<>(this, support, arg);
support.onStatementAdded(ret);
- addEffectiveSubstatement(ret);
return ret;
}
- /**
- * Adds an effective statement to collection of substatements.
- *
- * @param substatement substatement
- * @throws IllegalStateException if added in declared phase
- * @throws NullPointerException if statement parameter is null
- */
- public abstract void addEffectiveSubstatement(Mutable<?, ?, ?> substatement);
-
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;
}
- /**
- * Adds an effective statement to collection of substatements.
- *
- * @param statements substatements
- * @throws IllegalStateException
- * if added in declared phase
- * @throws NullPointerException
- * if statement parameter is null
- */
+ static final void afterAddEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
+ // Undeclared statements still need to have 'onDeclarationFinished()' triggered
+ if (substatement instanceof UndeclaredStmtCtx) {
+ finishDeclaration((UndeclaredStmtCtx<?, ?, ?>) substatement);
+ }
+ }
+
+ // Split out to keep generics working without a warning
+ private static <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> void finishDeclaration(
+ final UndeclaredStmtCtx<X, Y, Z> substatement) {
+ substatement.definition().onDeclarationFinished(substatement, ModelProcessingPhase.FULL_DECLARATION);
+ }
+
+ @Override
public final void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
if (!statements.isEmpty()) {
statements.forEach(StatementContextBase::verifyStatement);
return resized;
}
- abstract Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete();
+ abstract Iterator<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
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,
return result;
}
- @NonNull E createEffective(final StatementFactory<A, D, E> factory) {
- return createEffective(factory, this);
- }
-
- // Creates EffectiveStatement through full materialization
- static <A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> @NonNull E createEffective(
- final StatementFactory<A, D, E> factory, final StatementContextBase<A, D, E> ctx) {
- return factory.createEffective(ctx, ctx.streamDeclared(), ctx.streamEffective());
- }
+ abstract @NonNull E createEffective(@NonNull StatementFactory<A, D, E> factory);
/**
* Return a stream of declared statements which can be built into an {@link EffectiveStatement}, as per
for (final StatementContextBase<?, ?, ?> child : mutableDeclaredSubstatements()) {
finished &= child.tryToCompletePhase(targetOrder);
}
- for (final ReactorStmtCtx<?, ?, ?> child : effectiveChildrenToComplete()) {
- finished &= child.tryToCompletePhase(targetOrder);
+ final var it = effectiveChildrenToComplete();
+ while (it.hasNext()) {
+ finished &= it.next().tryToCompletePhase(targetOrder);
}
return finished;
}
}
}
- /**
- * Ends declared section of current node.
- */
- void endDeclared(final ModelProcessingPhase phase) {
- definition.onDeclarationFinished(this, phase);
- }
-
@Override
final StatementDefinitionContext<A, D, E> definition() {
return definition;
}
@Override
- public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<@NonNull N> namespace,
- final KT key,final StmtContext<?, ?, ?> stmt) {
+ public final <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(
+ final Class<@NonNull N> namespace, final KT key,final StmtContext<?, ?, ?> stmt) {
addContextToNamespace(namespace, key, stmt);
}
@Override
- public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> parent, final CopyType type,
+ public final Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> parent, final CopyType type,
final QNameModule targetModule) {
checkEffectiveModelCompleted(this);
return Optional.ofNullable(copyAsChildOfImpl(parent, type, targetModule));
}
- private ReactorStmtCtx<A, D, E> copyAsChildOfImpl(final Mutable<?, ?, ?> parent, final CopyType type,
+ private @Nullable ReactorStmtCtx<A, D, E> copyAsChildOfImpl(final Mutable<?, ?, ?> parent, final CopyType type,
final QNameModule targetModule) {
final StatementSupport<A, D, E> support = definition.support();
final CopyPolicy policy = support.copyPolicy();
return null;
}
- parent.ensureCompletedPhase(copy);
+ parent.ensureCompletedExecution(copy);
return canReuseCurrent(copy) ? this : copy;
}
- private boolean canReuseCurrent(final ReactorStmtCtx<A, D, E> copy) {
+ private boolean canReuseCurrent(final @NonNull ReactorStmtCtx<A, D, E> copy) {
// Defer to statement factory to see if we can reuse this object. If we can and have only context-independent
// substatements we can reuse the object. More complex cases are handled indirectly via the copy.
return definition.getFactory().canReuseCurrent(copy, this, buildEffective().effectiveSubstatements())
final InferredStatementContext<X, Y, Z> copy;
if (implicitParent.isPresent()) {
- final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implicitParent.get());
- result = new SubstatementContext(this, def, original.sourceReference(), original.rawArgument(),
- original.argument(), type);
-
- final CopyType childCopyType;
- switch (type) {
- case ADDED_BY_AUGMENTATION:
- childCopyType = CopyType.ORIGINAL;
- break;
- case ADDED_BY_USES_AUGMENTATION:
- childCopyType = CopyType.ADDED_BY_USES;
- break;
- case ADDED_BY_USES:
- case ORIGINAL:
- default:
- childCopyType = type;
- }
+ result = new UndeclaredStmtCtx(this, implicitParent.orElseThrow(), original, type);
+ final CopyType childCopyType = switch (type) {
+ case ADDED_BY_AUGMENTATION -> CopyType.ORIGINAL;
+ case ADDED_BY_USES_AUGMENTATION -> CopyType.ADDED_BY_USES;
+ case ADDED_BY_USES, ORIGINAL -> type;
+ };
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);
}
"Attempted to copy statement %s which has completed phase %s", stmt, phase);
}
- @Beta
- // FIXME: this information should be exposed as a well-known Namespace
+ @Override
public final boolean hasImplicitParentSupport() {
return definition.getFactory() instanceof ImplicitParentAwareStatementSupport;
}
- @Beta
- public final StatementContextBase<?, ?, ?> wrapWithImplicit(final StatementContextBase<?, ?, ?> original) {
+ @Override
+ public final StmtContext<?, ?, ?> wrapWithImplicit(final StmtContext<?, ?, ?> original) {
final var optImplicit = definition.getImplicitParentFor(this, original.publicDefinition());
if (optImplicit.isEmpty()) {
return original;
}
- final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(optImplicit.orElseThrow());
- final CopyType type = original.history().getLastOperation();
- final SubstatementContext<?, ?, ?> result = new SubstatementContext(original.getParentContext(), def,
- original.sourceReference(), original.rawArgument(), original.argument(), type);
+ checkArgument(original instanceof StatementContextBase, "Unsupported original %s", original);
+ final var origBase = (StatementContextBase<?, ?, ?>)original;
- result.addEffectiveSubstatement(original.reparent(result));
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ final UndeclaredStmtCtx<?, ?, ?> result = new UndeclaredStmtCtx(origBase, optImplicit.orElseThrow());
+ result.addEffectiveSubstatement(origBase.reparent(result));
result.setCompletedPhase(original.getCompletedPhase());
return result;
}