Refactor Leaf(List)EffectiveStatementImpl 15/86815/24
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 8 Jan 2020 23:22:32 +0000 (00:22 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 14 Jan 2020 13:22:18 +0000 (14:22 +0100)
Leaf(List)EffectiveStatementImpl costs 88 bytes each instance in common
Linux deployment. This turns out to be unnecessary, as be can easily
drop the size to 32/40 (48 worst) bytes by splitting out well-known
constants. This can represent as much as 10% savings on retained heap.

Since the two statements are sharing mapping towards SchemaNode world,
we introduce EffectiveStatementMixins -- utility bridge interfaces,
which are implementing aspects of DocumentedNode and its subclasses
in terms of EffectiveStatement and some mixed-in state.

JIRA: YANGTOOLS-1065
Change-Id: Icdafc4a196d86d2a493a44523bc81b1024854acb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
16 files changed:
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStmtUtils.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java [deleted file]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java [deleted file]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java [new file with mode: 0644]

diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java
new file mode 100644 (file)
index 0000000..f359a48
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+/**
+ * Specialization of {@link BaseStatementSupport} for QName statement arguments.
+ *
+ * @param <D> Declared Statement representation
+ * @param <E> Effective Statement representation
+ */
+@Beta
+public abstract class BaseQNameStatementSupport<D extends DeclaredStatement<QName>,
+        E extends EffectiveStatement<QName, D>> extends AbstractQNameStatementSupport<D, E> {
+    protected BaseQNameStatementSupport(final StatementDefinition publicDefinition) {
+        super(publicDefinition);
+    }
+
+    @Override
+    public final E createEffective(final StmtContext<QName, D, E> ctx) {
+        final D declared = BaseStatementSupport.buildDeclared(ctx);
+        final ImmutableList<? extends EffectiveStatement<?, ?>> substatements =
+                BaseStatementSupport.buildEffectiveSubstatements(ctx);
+        return substatements.isEmpty() ? createEmptyEffective(ctx, declared)
+                : createEffective(ctx, declared, substatements);
+    }
+
+    protected abstract @NonNull E createEffective(@NonNull StmtContext<QName, D, E> ctx, @NonNull D declared,
+            @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> substatements);
+
+    protected abstract @NonNull E createEmptyEffective(@NonNull StmtContext<QName, D, E> ctx, @NonNull D declared);
+
+    protected static final <E extends EffectiveStatement<?, ?>> @Nullable E findFirstStatement(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> statements, final Class<E> type) {
+        return BaseStatementSupport.findFirstStatement(statements, type);
+    }
+
+    protected static final <A, E extends EffectiveStatement<A, ?>> A findFirstArgument(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> statements, final Class<E> type, final A defValue) {
+        return BaseStatementSupport.findFirstArgument(statements, type, defValue);
+    }
+}
index 012d7cbaf5665557e57ec533bb60e2739c0121ce..ffb357c4e672c422a690cea38f9e2d02872848c9 100644 (file)
@@ -17,6 +17,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
@@ -50,6 +51,22 @@ public abstract class BaseStatementSupport<A, D extends DeclaredStatement<A>,
 
     protected abstract @NonNull E createEmptyEffective(@NonNull StmtContext<A, D, E> ctx, @NonNull D declared);
 
+    protected static final <E extends EffectiveStatement<?, ?>> @Nullable E findFirstStatement(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> statements, final Class<E> type) {
+        for (EffectiveStatement<?, ?> stmt : statements) {
+            if (type.isInstance(stmt)) {
+                return type.cast(stmt);
+            }
+        }
+        return null;
+    }
+
+    protected static final <A, E extends EffectiveStatement<A, ?>> A findFirstArgument(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> statements, final Class<E> type, final A defValue) {
+        final @Nullable E stmt = findFirstStatement(statements, type);
+        return stmt != null ? stmt.argument() : defValue;
+    }
+
     static final <A, D extends DeclaredStatement<A>> @NonNull D buildDeclared(final StmtContext<A, D, ?> ctx) {
         /*
          * Share original instance of declared statement between all effective
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java
new file mode 100644 (file)
index 0000000..46f09b9
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
+import org.opendaylight.yangtools.yang.model.api.CopyableNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
+import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
+import org.opendaylight.yangtools.yang.model.api.MustDefinition;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+
+/**
+ * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or
+ * implementation helpers based on default methods, so the correct behavior can be logically centralized.
+ */
+@Beta
+public final class EffectiveStatementMixins {
+    // Marker interface requiring all mixins to be derived from EffectiveStatement.
+    private interface Mixin<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
+        @SuppressWarnings("unchecked")
+        default <T> Collection<T> filterEffectiveStatements(final Class<T> type) {
+            // Yeah, this is not nice, but saves one transformation
+            return (Collection<T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
+        }
+
+        default <T> List<T> filterEffectiveStatementsList(final Class<T> type) {
+            return effectiveSubstatements().stream().filter(type::isInstance).map(type::cast)
+                    .collect(ImmutableList.toImmutableList());
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link AddedByUsesAware}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface AddedByUsesMixin<A, D extends DeclaredStatement<A>>
+            extends EffectiveStatementWithFlags<A, D>, AddedByUsesAware {
+        @Override
+        default boolean isAddedByUses() {
+            return (flags() & FlagsBuilder.ADDED_BY_USES) != 0;
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
+        @Override
+        default Collection<MustDefinition> getMustConstraints() {
+            return filterEffectiveStatements(MustDefinition.class);
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link CopyableNode}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface CopyableMixin<A, D extends DeclaredStatement<A>> extends AddedByUsesMixin<A, D>, CopyableNode {
+        @Override
+        default boolean isAugmenting() {
+            return (flags() & FlagsBuilder.AUGMENTING) != 0;
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface DataSchemaNodeMixin<A, D extends DeclaredStatement<A>>
+            extends DataSchemaNode, CopyableMixin<A, D>, SchemaNodeMixin<A, D>, WhenConditionMixin<A, D> {
+        @Override
+        default boolean isConfiguration() {
+            return (flags() & FlagsBuilder.CONFIGURATION) != 0;
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link DocumentedNode}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface DocumentedNodeMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, DocumentedNode {
+        /**
+         * Bridge between {@link EffectiveStatementWithFlags} and
+         * {@link org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus}.
+         *
+         * @param <A> Argument type ({@link Void} if statement does not have argument.)
+         * @param <D> Class representing declared version of this statement.
+         */
+        interface WithStatus<A, D extends DeclaredStatement<A>>
+                extends EffectiveStatementWithFlags<A, D>, DocumentedNodeMixin<A, D>, DocumentedNode.WithStatus {
+            @Override
+            default Status getStatus() {
+                final int status = flags() & FlagsBuilder.MASK_STATUS;
+                switch (status) {
+                    case FlagsBuilder.STATUS_CURRENT:
+                        return Status.CURRENT;
+                    case FlagsBuilder.STATUS_DEPRECATED:
+                        return Status.DEPRECATED;
+                    case FlagsBuilder.STATUS_OBSOLETE:
+                        return Status.OBSOLETE;
+                    default:
+                        throw new IllegalStateException("Illegal status " + status);
+                }
+            }
+        }
+
+        @Override
+        default Optional<String> getDescription() {
+            return findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class);
+        }
+
+        @Override
+        default Optional<String> getReference() {
+            return findFirstEffectiveSubstatementArgument(ReferenceEffectiveStatement.class);
+        }
+
+        @Override
+        default List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return filterEffectiveStatementsList(UnknownSchemaNode.class);
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface MandatoryMixin<A, D extends DeclaredStatement<A>>
+            extends EffectiveStatementWithFlags<A, D>, MandatoryAware {
+        @Override
+        default boolean isMandatory() {
+            return (flags() & FlagsBuilder.MANDATORY) != 0;
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link SchemaNode}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface SchemaNodeMixin<A, D extends DeclaredStatement<A>>
+            extends DocumentedNodeMixin.WithStatus<A, D>, SchemaNode {
+        @Override
+        default QName getQName() {
+            return getPath().getLastComponent();
+        }
+    }
+
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface UserOrderedMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
+        default boolean userOrdered() {
+            return (flags() & FlagsBuilder.USER_ORDERED) != 0;
+        }
+    }
+
+    /**
+     * Helper used to locate the effective {@code when} statement and exposing its argument as per
+     * {@link WhenConditionAware}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
+        @Override
+        default Optional<RevisionAwareXPath> getWhenCondition() {
+            return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
+        }
+    }
+
+    /**
+     * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
+     * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface EffectiveStatementWithFlags<A, D extends DeclaredStatement<A>> extends Mixin<A, D> {
+        /**
+         * Return flags assicated with this statements. Flags can be built using {@link FlagsBuilder}.
+         *
+         * @return Flag field value (32 bits).
+         */
+        int flags();
+
+        @NonNullByDefault
+        final class FlagsBuilder implements Mutable {
+            // We still have 25 flags remaining
+            static final int STATUS_CURRENT       = 0x0001;
+            static final int STATUS_DEPRECATED    = 0x0002;
+            static final int STATUS_OBSOLETE      = 0x0003;
+            static final int MASK_STATUS          = 0x0003;
+
+            static final int CONFIGURATION        = 0x0004;
+            static final int MANDATORY            = 0x0008;
+
+            static final int AUGMENTING           = 0x0010;
+            static final int ADDED_BY_USES        = 0x0020;
+            private static final int MASK_HISTORY = 0x0030;
+
+            static final int USER_ORDERED         = 0x0040;
+
+            private int flags;
+
+            public FlagsBuilder setConfiguration(final boolean config) {
+                if (config) {
+                    flags |= CONFIGURATION;
+                } else {
+                    flags &= ~CONFIGURATION;
+                }
+                return this;
+            }
+
+            public FlagsBuilder setHistory(final CopyHistory history) {
+                int bits;
+                if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
+                    bits = AUGMENTING | ADDED_BY_USES;
+                } else {
+                    bits = 0;
+                    if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) {
+                        bits |= AUGMENTING;
+                    }
+                    if (history.contains(CopyType.ADDED_BY_USES)) {
+                        bits |= ADDED_BY_USES;
+                    }
+                }
+
+                flags = flags & ~MASK_HISTORY | bits;
+                return this;
+            }
+
+            public FlagsBuilder setMandatory(final boolean mandatory) {
+                if (mandatory) {
+                    flags |= MANDATORY;
+                } else {
+                    flags &= ~MANDATORY;
+                }
+                return this;
+            }
+
+            public FlagsBuilder setStatus(final Status status) {
+                final int bits;
+                switch (status) {
+                    case CURRENT:
+                        bits = STATUS_CURRENT;
+                        break;
+                    case DEPRECATED:
+                        bits = STATUS_DEPRECATED;
+                        break;
+                    case OBSOLETE:
+                        bits = STATUS_DEPRECATED;
+                        break;
+                    default:
+                        throw new IllegalStateException("Unhandled status " + status);
+                }
+
+                flags = flags & ~MASK_STATUS | bits;
+                return this;
+            }
+
+            public FlagsBuilder setUserOrdered(final boolean userOrdered) {
+                if (userOrdered) {
+                    flags |= USER_ORDERED;
+                } else {
+                    flags &= ~USER_ORDERED;
+                }
+                return this;
+            }
+
+            public int toFlags() {
+                return flags;
+            }
+        }
+    }
+}
index 1c5af12b04b10f1552946294c02e11341300f4e3..0b88f7139353ccf4e1348d5542734cbfceac1abc 100644 (file)
@@ -10,10 +10,12 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Optional;
 import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
@@ -48,19 +50,29 @@ public final class EffectiveStmtUtils {
     }
 
     public static Optional<ElementCountConstraint> createElementCountConstraint(final EffectiveStatement<?, ?> stmt) {
+        return createElementCountConstraint(
+            stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null),
+            stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null));
+    }
+
+    public static Optional<ElementCountConstraint> createElementCountConstraint(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        return createElementCountConstraint(
+            BaseQNameStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null),
+            BaseQNameStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null));
+    }
+
+    private static Optional<ElementCountConstraint> createElementCountConstraint(
+            final @Nullable Integer min, final @Nullable String max) {
         final Integer minElements;
-        final Optional<Integer> min = stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class);
-        if (min.isPresent()) {
-            final Integer m = min.get();
-            minElements = m > 0 ? m : null;
+        if (min != null) {
+            minElements = min > 0 ? min : null;
         } else {
             minElements = null;
         }
 
         final Integer maxElements;
-        final String max = stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class)
-                .orElse(UNBOUNDED_STR);
-        if (!UNBOUNDED_STR.equals(max)) {
+        if (max != null && !UNBOUNDED_STR.equals(max)) {
             final Integer m = Integer.valueOf(max);
             maxElements = m < Integer.MAX_VALUE ? m : null;
         } else {
@@ -70,7 +82,6 @@ public final class EffectiveStmtUtils {
         return ElementCountConstraint.forNullable(minElements, maxElements);
     }
 
-
     /**
      * Checks whether supplied type has any of specified default values marked
      * with an if-feature. This method creates mutable copy of supplied set of
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java
new file mode 100644 (file)
index 0000000..d9c599f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.leaf;
+
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataSchemaNodeMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MandatoryMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MustConstraintMixin;
+
+abstract class AbstractLeafEffectiveStatement extends AbstractDeclaredEffectiveStatement.Default<QName, LeafStatement>
+        implements LeafEffectiveStatement, LeafSchemaNode, DerivableSchemaNode,
+            DataSchemaNodeMixin<QName, LeafStatement>, MandatoryMixin<QName, LeafStatement>,
+            MustConstraintMixin<QName, LeafStatement> {
+    // Variable: either a single substatement or an ImmutableList
+    private final @NonNull Object substatements;
+    private final @NonNull SchemaPath path;
+    private final @NonNull TypeDefinition<?> type;
+    private final int flags;
+
+    AbstractLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        super(declared);
+        this.substatements = substatements.size() == 1 ? substatements.get(0) : substatements;
+        this.path = requireNonNull(path);
+        this.flags = flags;
+        // TODO: lazy instantiation?
+        this.type = buildType();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
+        if (substatements instanceof ImmutableList) {
+            return (ImmutableList<? extends EffectiveStatement<?, ?>>) substatements;
+        }
+        verify(substatements instanceof EffectiveStatement, "Unexpected substatement %s", substatements);
+        return ImmutableList.of((EffectiveStatement<?, ?>) substatements);
+    }
+
+    @Override
+    public final int flags() {
+        return flags;
+    }
+
+    @Override
+    public final @NonNull QName argument() {
+        return getQName();
+    }
+
+    @Override
+    public final @NonNull SchemaPath getPath() {
+        return path;
+    }
+
+    @Override
+    public final TypeDefinition<?> getType() {
+        return type;
+    }
+
+    private TypeDefinition<?> buildType() {
+        final TypeEffectiveStatement<?> typeStmt = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get();
+        final ConcreteTypeBuilder<?> builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(),
+            getPath());
+        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            if (stmt instanceof DefaultEffectiveStatement) {
+                builder.setDefaultValue(((DefaultEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof DescriptionEffectiveStatement) {
+                builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof ReferenceEffectiveStatement) {
+                builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof StatusEffectiveStatement) {
+                builder.setStatus(((StatusEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof UnitsEffectiveStatement) {
+                builder.setUnits(((UnitsEffectiveStatement)stmt).argument());
+            }
+        }
+        return builder.build();
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java
new file mode 100644 (file)
index 0000000..a72b500
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.leaf;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
+
+final class EmptyLeafEffectiveStatement extends AbstractLeafEffectiveStatement {
+    EmptyLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        super(declared, path, flags, substatements);
+    }
+
+    @Override
+    public Optional<LeafSchemaNode> getOriginal() {
+        return Optional.empty();
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java
deleted file mode 100644 (file)
index 3c66667..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.leaf;
-
-import java.util.Objects;
-import java.util.Optional;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder;
-import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes;
-import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareDataSchemaNode;
-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;
-
-final class LeafEffectiveStatementImpl extends AbstractEffectiveMustConstraintAwareDataSchemaNode<LeafStatement>
-        implements LeafEffectiveStatement, LeafSchemaNode, DerivableSchemaNode {
-    private final LeafSchemaNode original;
-    private final TypeDefinition<?> type;
-    private final String defaultStr;
-    private final String unitsStr;
-    private final boolean mandatory;
-
-    LeafEffectiveStatementImpl(final StmtContext<QName, LeafStatement, EffectiveStatement<QName, LeafStatement>> ctx) {
-        super(ctx);
-        this.original = (LeafSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
-
-        final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
-                firstSubstatementOfType(TypeEffectiveStatement.class), ctx.getStatementSourceReference(),
-                "Leaf is missing a 'type' statement");
-
-        String dflt = null;
-        String units = null;
-        final ConcreteTypeBuilder<?> builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(),
-            ctx.getSchemaPath().get());
-        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
-            if (stmt instanceof DefaultEffectiveStatement) {
-                dflt = ((DefaultEffectiveStatement)stmt).argument();
-                builder.setDefaultValue(stmt.argument());
-            } else if (stmt instanceof DescriptionEffectiveStatement) {
-                builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof ReferenceEffectiveStatement) {
-                builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof StatusEffectiveStatement) {
-                builder.setStatus(((StatusEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof UnitsEffectiveStatement) {
-                units = ((UnitsEffectiveStatement)stmt).argument();
-                builder.setUnits(units);
-            }
-        }
-
-        SourceException.throwIf(
-            EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, dflt),
-            ctx.getStatementSourceReference(),
-            "Leaf '%s' has default value '%s' marked with an if-feature statement.", ctx.getStatementArgument(), dflt);
-
-        defaultStr = dflt;
-        unitsStr = units;
-        type = builder.build();
-        mandatory = findFirstEffectiveSubstatementArgument(MandatoryEffectiveStatement.class).orElse(Boolean.FALSE)
-                .booleanValue();
-    }
-
-    @Override
-    public boolean isMandatory() {
-        return mandatory;
-    }
-
-    @Override
-    public Optional<LeafSchemaNode> getOriginal() {
-        return Optional.ofNullable(original);
-    }
-
-    @Override
-    public TypeDefinition<?> getType() {
-        return type;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + Objects.hashCode(getQName());
-        result = prime * result + Objects.hashCode(getPath());
-        return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof LeafEffectiveStatementImpl)) {
-            return false;
-        }
-        final LeafEffectiveStatementImpl other = (LeafEffectiveStatementImpl) obj;
-        return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
-    }
-
-    @Override
-    public String toString() {
-        return LeafEffectiveStatementImpl.class.getSimpleName() + "["
-                + "qname=" + getQName()
-                + ", path=" + getPath()
-                + "]";
-    }
-}
index 488009e37007169d82508eccbc7f04dac17e46a4..fdc13903d7a422fe87902e4c75e9c08f3b463ef9 100644 (file)
@@ -7,19 +7,30 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.leaf;
 
+import com.google.common.collect.ImmutableList;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
+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.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
-public final class LeafStatementSupport
-        extends AbstractQNameStatementSupport<LeafStatement, EffectiveStatement<QName, LeafStatement>> {
+public final class LeafStatementSupport extends BaseQNameStatementSupport<LeafStatement, LeafEffectiveStatement> {
     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
         .LEAF)
         .addOptional(YangStmtMapping.CONFIG)
@@ -50,13 +61,12 @@ public final class LeafStatementSupport
     }
 
     @Override
-    public void onStatementAdded(final Mutable<QName, LeafStatement, EffectiveStatement<QName, LeafStatement>> stmt) {
+    public void onStatementAdded(final Mutable<QName, LeafStatement, LeafEffectiveStatement> stmt) {
         stmt.coerceParentContext().addToNs(ChildSchemaNodeNamespace.class, stmt.coerceStatementArgument(), stmt);
     }
 
     @Override
-    public void onFullDefinitionDeclared(
-            final Mutable<QName, LeafStatement, EffectiveStatement<QName, LeafStatement>> ctx) {
+    public void onFullDefinitionDeclared(final Mutable<QName, LeafStatement, LeafEffectiveStatement> ctx) {
         super.onFullDefinitionDeclared(ctx);
         StmtContextUtils.validateIfFeatureAndWhenOnListKeys(ctx);
     }
@@ -67,13 +77,40 @@ public final class LeafStatementSupport
     }
 
     @Override
-    public EffectiveStatement<QName, LeafStatement> createEffective(
-            final StmtContext<QName, LeafStatement, EffectiveStatement<QName, LeafStatement>> ctx) {
-        return new LeafEffectiveStatementImpl(ctx);
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
     }
 
     @Override
-    protected SubstatementValidator getSubstatementValidator() {
-        return SUBSTATEMENT_VALIDATOR;
+    protected LeafEffectiveStatement createEffective(
+            final StmtContext<QName, LeafStatement, LeafEffectiveStatement> ctx, final LeafStatement declared,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
+            findFirstStatement(substatements, TypeEffectiveStatement.class), ctx.getStatementSourceReference(),
+                "Leaf is missing a 'type' statement");
+        final String dflt = findFirstArgument(substatements, DefaultEffectiveStatement.class, null);
+        SourceException.throwIf(
+            EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, dflt),
+            ctx.getStatementSourceReference(),
+            "Leaf '%s' has default value '%s' marked with an if-feature statement.", ctx.getStatementArgument(), dflt);
+
+        final SchemaPath path = ctx.getSchemaPath().get();
+        final LeafSchemaNode original = (LeafSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective)
+                .orElse(null);
+        final int flags = new FlagsBuilder()
+                .setHistory(ctx.getCopyHistory())
+                .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))
+                .setConfiguration(ctx.isConfiguration())
+                .setMandatory(findFirstArgument(substatements, MandatoryEffectiveStatement.class, Boolean.FALSE))
+                .toFlags();
+
+        return original == null ? new EmptyLeafEffectiveStatement(declared, path, flags, substatements)
+                : new RegularLeafEffectiveStatement(declared, path, flags, substatements, original);
+    }
+
+    @Override
+    protected LeafEffectiveStatement createEmptyEffective(
+            final StmtContext<QName, LeafStatement, LeafEffectiveStatement> ctx, final LeafStatement declared) {
+        throw new UnsupportedOperationException("Leaf statements must have at least one substatement");
     }
-}
\ No newline at end of file
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java
new file mode 100644 (file)
index 0000000..2835643
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.leaf;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
+
+final class RegularLeafEffectiveStatement extends AbstractLeafEffectiveStatement {
+    private final @Nullable LeafSchemaNode original;
+
+    RegularLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements, final LeafSchemaNode original) {
+        super(declared, path, flags, substatements);
+        this.original = original;
+    }
+
+    @Override
+    public Optional<LeafSchemaNode> getOriginal() {
+        return Optional.ofNullable(original);
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java
new file mode 100644 (file)
index 0000000..bd30991
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.leaf_list;
+
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder;
+import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataSchemaNodeMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MustConstraintMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.UserOrderedMixin;
+
+abstract class AbstractLeafListEffectiveStatement
+        extends AbstractDeclaredEffectiveStatement.Default<QName, LeafListStatement>
+        implements LeafListEffectiveStatement, LeafListSchemaNode, DerivableSchemaNode,
+            UserOrderedMixin<QName, LeafListStatement>, DataSchemaNodeMixin<QName, LeafListStatement>,
+            MustConstraintMixin<QName, LeafListStatement> {
+    // Variable: either a single substatement or an ImmutableList
+    private final @NonNull Object substatements;
+    private final @NonNull SchemaPath path;
+    private final @NonNull TypeDefinition<?> type;
+    private final int flags;
+
+    AbstractLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        super(declared);
+        this.substatements = substatements.size() == 1 ? substatements.get(0) : substatements;
+        this.path = requireNonNull(path);
+        this.flags = flags;
+        // TODO: lazy instantiation?
+        this.type = buildType();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
+        if (substatements instanceof ImmutableList) {
+            return (ImmutableList<? extends EffectiveStatement<?, ?>>) substatements;
+        }
+        verify(substatements instanceof EffectiveStatement, "Unexpected substatement %s", substatements);
+        return ImmutableList.of((EffectiveStatement<?, ?>) substatements);
+    }
+
+    @Override
+    public final int flags() {
+        return flags;
+    }
+
+    @Override
+    public final @NonNull QName argument() {
+        return getQName();
+    }
+
+    @Override
+    public final @NonNull SchemaPath getPath() {
+        return path;
+    }
+
+    @Override
+    public final TypeDefinition<?> getType() {
+        return type;
+    }
+
+    @Override
+    public final boolean isUserOrdered() {
+        return userOrdered();
+    }
+
+    @Override
+    public final int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Objects.hashCode(getQName());
+        result = prime * result + Objects.hashCode(getPath());
+        return result;
+    }
+
+    @Override
+    public final boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof AbstractLeafListEffectiveStatement)) {
+            return false;
+        }
+        final AbstractLeafListEffectiveStatement other = (AbstractLeafListEffectiveStatement) obj;
+        return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
+    }
+
+    @Override
+    public final String toString() {
+        return getClass().getSimpleName() + "[" + getQName() + "]";
+    }
+
+    private TypeDefinition<?> buildType() {
+        final TypeEffectiveStatement<?> typeStmt = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get();
+        final ConcreteTypeBuilder<?> builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(),
+            getPath());
+        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            // NOTE: 'default' is ommitted here on purpose
+            if (stmt instanceof DescriptionEffectiveStatement) {
+                builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof ReferenceEffectiveStatement) {
+                builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof StatusEffectiveStatement) {
+                builder.setStatus(((StatusEffectiveStatement)stmt).argument());
+            } else if (stmt instanceof UnitsEffectiveStatement) {
+                builder.setUnits(((UnitsEffectiveStatement)stmt).argument());
+            }
+        }
+        return builder.build();
+    }
+}
index 9ecb77f3e8df93e73b07b60ae046b3cc4e4f330b..9dda6fbeb5f5b8a9833d717951a7aac9090ddddd 100644 (file)
@@ -7,26 +7,39 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.leaf_list;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Optional;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
+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.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 abstract class AbstractLeafListStatementSupport
-        extends AbstractQNameStatementSupport<LeafListStatement, EffectiveStatement<QName, LeafListStatement>> {
-
+        extends BaseQNameStatementSupport<LeafListStatement, LeafListEffectiveStatement> {
     AbstractLeafListStatementSupport() {
         super(YangStmtMapping.LEAF_LIST);
     }
 
     @Override
-    public final void onStatementAdded(
-            final Mutable<QName, LeafListStatement, EffectiveStatement<QName, LeafListStatement>> stmt) {
+    public final void onStatementAdded(final Mutable<QName, LeafListStatement, LeafListEffectiveStatement> stmt) {
         stmt.coerceParentContext().addToNs(ChildSchemaNodeNamespace.class, stmt.coerceStatementArgument(), stmt);
     }
 
@@ -41,8 +54,58 @@ abstract class AbstractLeafListStatementSupport
     }
 
     @Override
-    public final EffectiveStatement<QName, LeafListStatement> createEffective(
-            final StmtContext<QName, LeafListStatement, EffectiveStatement<QName, LeafListStatement>> ctx) {
-        return new LeafListEffectiveStatementImpl(ctx);
+    protected final LeafListEffectiveStatement createEffective(
+            final StmtContext<QName, LeafListStatement, LeafListEffectiveStatement> ctx,
+            final LeafListStatement declared,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
+            findFirstStatement(substatements, TypeEffectiveStatement.class), ctx.getStatementSourceReference(),
+                "Leaf-list is missing a 'type' statement");
+
+        final SchemaPath path = ctx.getSchemaPath().get();
+        final LeafListSchemaNode original = (LeafListSchemaNode) ctx.getOriginalCtx()
+                .map(StmtContext::buildEffective).orElse(null);
+
+        final int flags = new FlagsBuilder()
+                .setHistory(ctx.getCopyHistory())
+                .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))
+                .setConfiguration(ctx.isConfiguration())
+                .setUserOrdered(findFirstArgument(substatements, OrderedByEffectiveStatement.class, "system")
+                    .equals("user"))
+                .toFlags();
+        final ImmutableSet<String> defaultValues = substatements.stream()
+                .filter(DefaultEffectiveStatement.class::isInstance)
+                .map(DefaultEffectiveStatement.class::cast)
+                .map(DefaultEffectiveStatement::argument)
+                .collect(ImmutableSet.toImmutableSet());
+
+        // FIXME: We need to interpret the default value in terms of supplied element type
+        SourceException.throwIf(
+            EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, defaultValues),
+            ctx.getStatementSourceReference(),
+            "Leaf-list '%s' has one of its default values '%s' marked with an if-feature statement.",
+            ctx.getStatementArgument(), defaultValues);
+
+        // FIXME: RFC7950 section 7.7.4: we need to check for min-elements and defaultValues conflict
+
+        final Optional<ElementCountConstraint> elementCountConstraint =
+                EffectiveStmtUtils.createElementCountConstraint(substatements);
+
+        if (defaultValues.isEmpty()) {
+            return original == null && !elementCountConstraint.isPresent()
+                    ? new EmptyLeafListEffectiveStatement(declared, path, flags, substatements)
+                            : new SlimLeafListEffectiveStatement(declared, path, flags, substatements, original,
+                                elementCountConstraint.orElse(null));
+        }
+
+        return new RegularLeafListEffectiveStatement(declared, path, flags, substatements, original, defaultValues,
+            elementCountConstraint.orElse(null));
+    }
+
+    @Override
+    protected final LeafListEffectiveStatement createEmptyEffective(
+            final StmtContext<QName, LeafListStatement, LeafListEffectiveStatement> ctx,
+            final LeafListStatement declared) {
+        throw new UnsupportedOperationException("Leaf statements must have at least one substatement");
     }
 }
\ No newline at end of file
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java
new file mode 100644 (file)
index 0000000..950f2bc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.leaf_list;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+
+abstract class AbstractNonEmptyLeafListEffectiveStatement extends AbstractLeafListEffectiveStatement {
+    private final @Nullable LeafListSchemaNode original;
+    private final @Nullable ElementCountConstraint elementCountConstraint;
+
+    AbstractNonEmptyLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements,
+            final LeafListSchemaNode original, final ElementCountConstraint elementCountConstraint) {
+        super(declared, path, flags, substatements);
+        this.original = original;
+        this.elementCountConstraint = elementCountConstraint;
+    }
+
+    @Override
+    public final Optional<LeafListSchemaNode> getOriginal() {
+        return Optional.ofNullable(original);
+    }
+
+    @Override
+    public final Optional<ElementCountConstraint> getElementCountConstraint() {
+        return Optional.ofNullable(elementCountConstraint);
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java
new file mode 100644 (file)
index 0000000..7905da1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.leaf_list;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+
+final class EmptyLeafListEffectiveStatement extends AbstractLeafListEffectiveStatement {
+    EmptyLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        super(declared, path, flags, substatements);
+    }
+
+    @Override
+    public Optional<LeafSchemaNode> getOriginal() {
+        return Optional.empty();
+    }
+
+    @Override
+    public @NonNull Collection<? extends Object> getDefaults() {
+        return ImmutableSet.of();
+    }
+
+    @Override
+    public Optional<ElementCountConstraint> getElementCountConstraint() {
+        return Optional.empty();
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java
deleted file mode 100644 (file)
index 6edbb70..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.leaf_list;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder;
-import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes;
-import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareDataSchemaNode;
-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;
-
-final class LeafListEffectiveStatementImpl extends AbstractEffectiveMustConstraintAwareDataSchemaNode<LeafListStatement>
-        implements LeafListEffectiveStatement, LeafListSchemaNode, DerivableSchemaNode {
-
-    private static final String ORDER_BY_USER_KEYWORD = "user";
-
-    private final TypeDefinition<?> type;
-    private final LeafListSchemaNode original;
-    private final boolean userOrdered;
-    private final @NonNull ImmutableSet<String> defaultValues;
-    private final ElementCountConstraint elementCountConstraint;
-
-    LeafListEffectiveStatementImpl(
-            final StmtContext<QName, LeafListStatement, EffectiveStatement<QName, LeafListStatement>> ctx) {
-        super(ctx);
-        this.original = (LeafListSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
-
-        final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
-            firstSubstatementOfType(TypeEffectiveStatement.class), ctx.getStatementSourceReference(),
-            "Leaf-list is missing a 'type' statement");
-
-        final ConcreteTypeBuilder<?> builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(),
-            ctx.getSchemaPath().get());
-        final ImmutableSet.Builder<String> defaultValuesBuilder = ImmutableSet.builder();
-        boolean isUserOrdered = false;
-        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
-            if (stmt instanceof OrderedByEffectiveStatement) {
-                isUserOrdered = ORDER_BY_USER_KEYWORD.equals(stmt.argument());
-            }
-
-            if (stmt instanceof DefaultEffectiveStatement) {
-                defaultValuesBuilder.add(((DefaultEffectiveStatement) stmt).argument());
-            } else if (stmt instanceof DescriptionEffectiveStatement) {
-                builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof ReferenceEffectiveStatement) {
-                builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof StatusEffectiveStatement) {
-                builder.setStatus(((StatusEffectiveStatement)stmt).argument());
-            } else if (stmt instanceof UnitsEffectiveStatement) {
-                builder.setUnits(((UnitsEffectiveStatement)stmt).argument());
-            }
-        }
-
-        // FIXME: We need to interpret the default value in terms of supplied element type
-        defaultValues = defaultValuesBuilder.build();
-        SourceException.throwIf(
-            EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, defaultValues),
-            ctx.getStatementSourceReference(),
-            "Leaf-list '%s' has one of its default values '%s' marked with an if-feature statement.",
-            ctx.getStatementArgument(), defaultValues);
-
-        // FIXME: RFC7950 section 7.7.4: we need to check for min-elements and defaultValues conflict
-
-        type = builder.build();
-        userOrdered = isUserOrdered;
-        elementCountConstraint = EffectiveStmtUtils.createElementCountConstraint(this).orElse(null);
-    }
-
-    @Override
-    public Collection<String> getDefaults() {
-        return defaultValues;
-    }
-
-    @Override
-    public Optional<LeafListSchemaNode> getOriginal() {
-        return Optional.ofNullable(original);
-    }
-
-    @Override
-    public TypeDefinition<?> getType() {
-        return type;
-    }
-
-    @Override
-    public boolean isUserOrdered() {
-        return userOrdered;
-    }
-
-    @Override
-    public Optional<ElementCountConstraint> getElementCountConstraint() {
-        return Optional.ofNullable(elementCountConstraint);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + Objects.hashCode(getQName());
-        result = prime * result + Objects.hashCode(getPath());
-        return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final LeafListEffectiveStatementImpl other = (LeafListEffectiveStatementImpl) obj;
-        return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
-    }
-
-    @Override
-    public String toString() {
-        return LeafListEffectiveStatementImpl.class.getSimpleName() + "[" + getQName() + "]";
-    }
-}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java
new file mode 100644 (file)
index 0000000..d03f3d0
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.leaf_list;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+
+final class RegularLeafListEffectiveStatement extends AbstractNonEmptyLeafListEffectiveStatement {
+    private final @NonNull ImmutableSet<String> defaults;
+
+    RegularLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements, final LeafListSchemaNode original,
+            final ImmutableSet<String> defaults, final ElementCountConstraint elementCountConstraint) {
+        super(declared, path, flags, substatements, original, elementCountConstraint);
+        this.defaults = requireNonNull(defaults);
+    }
+
+    @Override
+    public ImmutableSet<String> getDefaults() {
+        return defaults;
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java
new file mode 100644 (file)
index 0000000..fdc7be3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.leaf_list;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
+
+final class SlimLeafListEffectiveStatement extends AbstractNonEmptyLeafListEffectiveStatement {
+    SlimLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements,
+            final LeafListSchemaNode original, final ElementCountConstraint elementCountConstraint) {
+        super(declared, path, flags, substatements, original, elementCountConstraint);
+    }
+
+    @Override
+    public ImmutableSet<String> getDefaults() {
+        return ImmutableSet.of();
+    }
+}