From: Robert Varga Date: Wed, 5 Feb 2020 21:37:34 +0000 (+0100) Subject: Refactor typedef implementations X-Git-Tag: v4.0.7~7 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=bbf971988a385a8df74cb99a3b8c668b1c9c559b;p=yangtools.git Refactor typedef implementations A typical typedef costs about 56 bytes, which is a bit heavy given that good models have a lot of these. Optimize layout and offload type definition builder. JIRA: YANGTOOLS-1065 Change-Id: I71fe350edec3ce015dabf36936e6f37bb41b3f8e Signed-off-by: Robert Varga --- diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeEffectiveStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeEffectiveStatement.java index 3b5288501a..847d982e50 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeEffectiveStatement.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeEffectiveStatement.java @@ -7,9 +7,14 @@ */ package org.opendaylight.yangtools.yang.model.api.stmt; +import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; public interface TypeEffectiveStatement extends EffectiveStatement, TypeDefinitionAware { - + @Override + default StatementDefinition statementDefinition() { + return YangStmtMapping.TYPE; + } } diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeStatement.java index 41887f65bb..02d5c81b4b 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeStatement.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypeStatement.java @@ -13,10 +13,17 @@ import java.util.Collection; import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; @Rfc6020AbnfRule("type-stmt") public interface TypeStatement extends DeclaredStatement { + @Override + default StatementDefinition statementDefinition() { + return YangStmtMapping.TYPE; + } + default @NonNull String getName() { // FIXME: YANGTOOLS-908: verifyNotNull() should not be needed here return verifyNotNull(argument()); diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefEffectiveStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefEffectiveStatement.java index da3b3e977a..b14059a45d 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefEffectiveStatement.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefEffectiveStatement.java @@ -10,12 +10,18 @@ package org.opendaylight.yangtools.yang.model.api.stmt; import com.google.common.annotations.Beta; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; /** * Effective model statement which should be used to derive application behaviour related to typedefs. */ public interface TypedefEffectiveStatement extends EffectiveStatement, TypeDefinitionAware { + @Override + default StatementDefinition statementDefinition() { + return YangStmtMapping.TYPEDEF; + } /** * Return this type definition as an effective type statement. diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefStatement.java index 2329c11844..ab2896c372 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefStatement.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/TypedefStatement.java @@ -11,9 +11,16 @@ import static com.google.common.base.Verify.verifyNotNull; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; public interface TypedefStatement extends DocumentedDeclaredStatement.WithStatus, TypeAwareDeclaredStatement, DefaultStatementAwareDeclaredStatement { + @Override + default StatementDefinition statementDefinition() { + return YangStmtMapping.TYPEDEF; + } + default @NonNull QName getName() { // FIXME: YANGTOOLS-908: verifyNotNull() should not be needed here return verifyNotNull(argument()); diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveSchemaNode.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveSchemaNode.java index 38fd53e1d2..ffa0ef9d18 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveSchemaNode.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveSchemaNode.java @@ -14,6 +14,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +@Deprecated(forRemoval = true) public abstract class AbstractEffectiveSchemaNode> extends AbstractSchemaEffectiveDocumentedNode implements SchemaNode { diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinEffectiveStatement.java index c8d4386a4b..87a9a1735e 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinEffectiveStatement.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinEffectiveStatement.java @@ -16,10 +16,8 @@ import java.util.Map; import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; -import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement; @@ -77,11 +75,6 @@ enum BuiltinEffectiveStatement implements TypeEffectiveStatement return ImmutableList.of(); } - @Override - public final StatementDefinition statementDefinition() { - return YangStmtMapping.TYPE; - } - @Override public final String argument() { return getTypeDefinition().getQName().getLocalName(); diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinTypeStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinTypeStatement.java index 3645272948..74fddd0c5f 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinTypeStatement.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/BuiltinTypeStatement.java @@ -15,7 +15,6 @@ import com.google.common.collect.ImmutableMap.Builder; import java.util.Collection; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; -import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement; @@ -77,11 +76,6 @@ final class BuiltinTypeStatement implements TypeStatement { return ImmutableList.of(); } - @Override - public StatementDefinition statementDefinition() { - return YangStmtMapping.TYPE; - } - @Override public StatementSource getStatementSource() { return StatementSource.DECLARATION; diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/EmptyTypedefStatement.java similarity index 58% rename from yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementImpl.java rename to yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/EmptyTypedefStatement.java index 59bb56a420..1d676195ef 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementImpl.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/EmptyTypedefStatement.java @@ -9,11 +9,10 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement; -import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredStatement.WithQNameArgument; -final class TypedefStatementImpl extends AbstractDeclaredStatement implements TypedefStatement { - TypedefStatementImpl(final StmtContext context) { - super(context); +final class EmptyTypedefStatement extends WithQNameArgument implements TypedefStatement { + EmptyTypedefStatement(final QName argument) { + super(argument); } } diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/RegularTypedefStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/RegularTypedefStatement.java new file mode 100644 index 0000000000..668c98582c --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/RegularTypedefStatement.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef; + +import com.google.common.collect.ImmutableList; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredStatement.WithQNameArgument.WithSubstatements; + +final class RegularTypedefStatement extends WithSubstatements implements TypedefStatement { + RegularTypedefStatement(final QName argument, final ImmutableList> substatements) { + super(argument, substatements); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefEffectiveStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefEffectiveStatementImpl.java index 8ab0ae3ad4..f852caac42 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefEffectiveStatementImpl.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefEffectiveStatementImpl.java @@ -7,17 +7,19 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; import java.util.Collection; import java.util.Map; import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; -import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; -import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement; @@ -30,32 +32,74 @@ import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement; import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement; import org.opendaylight.yangtools.yang.model.util.type.DerivedTypeBuilder; import org.opendaylight.yangtools.yang.model.util.type.DerivedTypes; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveSchemaNode; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement.Default; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.SchemaNodeMixin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class TypedefEffectiveStatementImpl extends AbstractEffectiveSchemaNode implements - TypedefEffectiveStatement { +final class TypedefEffectiveStatementImpl extends Default + implements TypedefEffectiveStatement, SchemaNodeMixin { private static final Logger LOG = LoggerFactory.getLogger(TypedefEffectiveStatementImpl.class); - private final @NonNull TypeDefinition typeDefinition; + private final @NonNull Object substatements; + private final @NonNull SchemaPath path; + private final int flags; + private volatile TypeDefinition typeDefinition; private volatile TypeEffectiveStatement typeStatement; - TypedefEffectiveStatementImpl(final StmtContext ctx) { - super(ctx); + TypedefEffectiveStatementImpl(final TypedefStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements) { + super(declared); + this.path = requireNonNull(path); + this.flags = flags; + this.substatements = maskList(substatements); + } + + @Override + public int flags() { + return flags; + } + + @Override + public SchemaPath getPath() { + return path; + } + + @Override + public @NonNull QName argument() { + return getQName(); + } + + @Override + public ImmutableList> effectiveSubstatements() { + return unmaskList(substatements); + } + + @Override + public TypeDefinition getTypeDefinition() { + final TypeDefinition existing = typeDefinition; + return existing != null ? existing : loadTypeDefinition(); + } + + @Override + public TypeEffectiveStatement asTypeEffectiveStatement() { + final TypeEffectiveStatement local = typeStatement; + return local != null ? local : loadTypeStatement(); + } + + private synchronized @NonNull TypeDefinition loadTypeDefinition() { + final TypeDefinition existing = typeDefinition; + if (existing != null) { + return existing; + } + + final TypeEffectiveStatement type = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get(); + final DerivedTypeBuilder builder = DerivedTypes.derivedTypeBuilder(type.getTypeDefinition(), path); - final TypeEffectiveStatement typeEffectiveStmt = firstSubstatementOfType(TypeEffectiveStatement.class); - final DerivedTypeBuilder builder = DerivedTypes.derivedTypeBuilder(typeEffectiveStmt.getTypeDefinition(), - ctx.getSchemaPath().get()); - String dflt = null; for (final EffectiveStatement stmt : effectiveSubstatements()) { if (stmt instanceof DefaultEffectiveStatement) { - dflt = ((DefaultEffectiveStatement) stmt).argument(); - builder.setDefaultValue(dflt); + builder.setDefaultValue(((DefaultEffectiveStatement) stmt).argument()); } else if (stmt instanceof DescriptionEffectiveStatement) { builder.setDescription(((DescriptionEffectiveStatement)stmt).argument()); } else if (stmt instanceof ReferenceEffectiveStatement) { @@ -67,39 +111,21 @@ final class TypedefEffectiveStatementImpl extends AbstractEffectiveSchemaNode getTypeDefinition() { - return typeDefinition; + final TypeDefinition ret = builder.build(); + typeDefinition = ret; + return ret; } - @Override - public TypeEffectiveStatement asTypeEffectiveStatement() { + private synchronized @NonNull TypeEffectiveStatement loadTypeStatement() { TypeEffectiveStatement ret = typeStatement; if (ret == null) { - synchronized (this) { - ret = typeStatement; - if (ret == null) { - typeStatement = ret = new ProxyTypeEffectiveStatement(); - } - } + typeStatement = ret = new ProxyTypeEffectiveStatement(); } - return ret; } @@ -125,11 +151,6 @@ final class TypedefEffectiveStatementImpl extends AbstractEffectiveSchemaNode { + BaseQNameStatementSupport { private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder( YangStmtMapping.TYPEDEF) .addOptional(YangStmtMapping.DEFAULT) @@ -45,27 +54,6 @@ public final class TypedefStatementSupport extends return StmtContextUtils.parseIdentifier(ctx, value); } - @Override - public TypedefStatement createDeclared(final StmtContext ctx) { - // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to ensure - // that a typedef in child scope does not shadow a typedef in parent scope which occurs later in the text. - final StmtContext parent = ctx.getParentContext(); - if (parent != null) { - final StmtContext grandParent = parent.getParentContext(); - if (grandParent != null) { - checkConflict(grandParent, ctx); - } - } - - return new TypedefStatementImpl(ctx); - } - - @Override - public TypedefEffectiveStatement createEffective( - final StmtContext ctx) { - return new TypedefEffectiveStatementImpl(ctx); - } - @Override public void onFullDefinitionDeclared(final Mutable stmt) { super.onFullDefinitionDeclared(stmt); @@ -86,6 +74,43 @@ public final class TypedefStatementSupport extends return SUBSTATEMENT_VALIDATOR; } + @Override + protected TypedefStatement createDeclared(final StmtContext ctx, + final ImmutableList> substatements) { + checkDeclared(ctx); + return new RegularTypedefStatement(ctx.coerceStatementArgument(), substatements); + } + + @Override + protected TypedefStatement createEmptyDeclared(final StmtContext ctx) { + checkDeclared(ctx); + return new EmptyTypedefStatement(ctx.coerceStatementArgument()); + } + + @Override + protected TypedefEffectiveStatement createEffective( + final StmtContext ctx, + final TypedefStatement declared, final ImmutableList> substatements) { + final TypeEffectiveStatement typeEffectiveStmt = findFirstStatement(substatements, + TypeEffectiveStatement.class); + final String dflt = findFirstArgument(substatements, DefaultEffectiveStatement.class, null); + SourceException.throwIf( + EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeEffectiveStmt, dflt), + ctx.getStatementSourceReference(), + "Typedef '%s' has default value '%s' marked with an if-feature statement.", ctx.getStatementArgument(), + dflt); + + return new TypedefEffectiveStatementImpl(declared, ctx.getSchemaPath().get(), computeFlags(substatements), + substatements); + } + + @Override + protected TypedefEffectiveStatement createEmptyEffective( + final StmtContext ctx, + final TypedefStatement declared) { + throw new IllegalStateException("Refusing to create empty typedef for " + declared); + } + private static void checkConflict(final StmtContext parent, final StmtContext stmt) { final QName arg = stmt.coerceStatementArgument(); final StmtContext existing = parent.getFromNamespace(TypeNamespace.class, arg); @@ -93,4 +118,22 @@ public final class TypedefStatementSupport extends SourceException.throwIf(existing != null, stmt.getStatementSourceReference(), "Duplicate name for typedef %s", arg); } + + private static void checkDeclared(final StmtContext ctx) { + // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to ensure + // that a typedef in child scope does not shadow a typedef in parent scope which occurs later in the text. + final StmtContext parent = ctx.getParentContext(); + if (parent != null) { + final StmtContext grandParent = parent.getParentContext(); + if (grandParent != null) { + checkConflict(grandParent, ctx); + } + } + } + + private static int computeFlags(final ImmutableList> substatements) { + return new FlagsBuilder() + .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT)) + .toFlags(); + } } \ No newline at end of file