From: Robert Varga Date: Fri, 7 Jul 2017 00:22:06 +0000 (+0200) Subject: BUG-6972: Add OptionaBoolean utility X-Git-Tag: release/carbon-sr2~17 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=e856047ff9cd6b5cfca9b59d4ef7c289df8f0782;p=yangtools.git BUG-6972: Add OptionaBoolean utility This utility allows us to store an optional boolean in a byte field, reducing the cost from 2 bytes (two boolean fields) or 4/8 bytes (reference) to a single byte. Also converts eligible classes. Trims down StatementContextBase and DeviateEffectiveStatementImpl. Change-Id: I5444bd4bb7aa0ea52202b08fcfcf9207ea045fa9 Signed-off-by: Robert Varga --- diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/OptionalBoolean.java b/common/util/src/main/java/org/opendaylight/yangtools/util/OptionalBoolean.java new file mode 100644 index 0000000000..824dbe6e47 --- /dev/null +++ b/common/util/src/main/java/org/opendaylight/yangtools/util/OptionalBoolean.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, 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.util; + +import com.google.common.annotations.Beta; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * Utility class for storing an optional boolean in a single byte value. This cuts down the memory requirement quite + * at very small computational cost. + * + *

+ * Note: fields do not have to be explicitly initialized, as default initialization value for 'byte', 0, is used to + * represent 'absent' condition. + * + * @author Robert Varga + */ +@Beta +public final class OptionalBoolean { + private static final byte ABSENT = 0; + private static final byte FALSE = 1; + private static final byte TRUE = 2; + + private OptionalBoolean() { + throw new UnsupportedOperationException(); + } + + /** + * Check if a field value has been set, just like {@link Optional#isPresent()}. + * + * @param value field value + * @return True if the value is set. + * @throws IllegalArgumentException if value is invalid + */ + public static boolean isPresent(final byte value) { + switch (value) { + case ABSENT: + return false; + case FALSE: + case TRUE: + return true; + default: + throw invalidValue(value); + } + } + + /** + * Decode boolean from a field value, just like {@link Optional#get()}. + * + * @param value Field value + * @return Decoded boolean. + * @throws IllegalArgumentException if value is invalid + * @throws IllegalStateException if value has not been set + */ + public static boolean get(final byte value) { + switch (value) { + case ABSENT: + throw new IllegalStateException("Field has not been initialized"); + case FALSE: + return false; + case TRUE: + return true; + default: + throw invalidValue(value); + } + } + + /** + * Encode a boolean to a field value, just like {@link Optional#of(Object)}. + * + * @param bool Boolean value. + * @return Field value. + */ + public static byte of(final boolean bool) { + return bool ? TRUE : FALSE; + } + + /** + * Convert a nullable {@link Boolean} into a field value, just like {@link Optional#ofNullable(Object)}. + * + * @param bool Boolean value. + * @return Field value. + */ + public static byte ofNullable(final @Nullable Boolean bool) { + return bool == null ? ABSENT : of(bool.booleanValue()); + } + + /** + * Convert a field value to a nullable {@link Boolean}. Similar to {@code Optional.orElse(null)}. + * + * @param value Fied value. + * @return Nullable Boolean. + */ + public static @Nullable Boolean toNullable(final byte value) { + switch (value) { + case ABSENT: + return null; + case FALSE: + return Boolean.FALSE; + case TRUE: + return Boolean.TRUE; + default: + throw invalidValue(value); + } + } + + /** + * Convert a field value into an {@link Optional} {@link Boolean}. + * + * @param value Field value. + * @return Optional {@link Boolean}. + * @throws IllegalArgumentException if value is invalid. + */ + public static Optional toOptional(final byte value) { + switch (value) { + case ABSENT: + return Optional.empty(); + case FALSE: + return Optional.of(Boolean.FALSE); + case TRUE: + return Optional.of(Boolean.TRUE); + default: + throw invalidValue(value); + } + } + + /** + * Convert a field value into a String representation. + * + * @param value Field value. + * @return Boolean-compatible string, or "absent". + * @throws IllegalArgumentException if value is invalid. + */ + public static String toString(final byte value) { + switch (value) { + case ABSENT: + return "absent"; + case FALSE: + return Boolean.toString(false); + case TRUE: + return Boolean.toString(true); + default: + throw invalidValue(value); + } + } + + private static IllegalArgumentException invalidValue(final byte value) { + throw new IllegalArgumentException("Invalid field value " + value); + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java index 6c148f50a6..5998202802 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.Optional; import java.util.Set; import javax.annotation.Nonnull; +import org.opendaylight.yangtools.util.OptionalBoolean; 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; @@ -91,13 +92,15 @@ public abstract class StatementContextBase, E private Collection> effectOfStatement = ImmutableList.of(); private StatementMap substatements = StatementMap.empty(); - private Boolean supportedByFeatures = null; private boolean isSupportedToBuildEffective = true; private ModelProcessingPhase completedPhase = null; private D declaredInstance; private E effectiveInstance; private int order = 0; + // BooleanFields value + private byte supportedByFeatures; + StatementContextBase(final StatementDefinitionContext def, final StatementSourceReference ref, final String rawArgument) { this.definition = Preconditions.checkNotNull(def); @@ -145,15 +148,19 @@ public abstract class StatementContextBase, E @Override public boolean isSupportedByFeatures() { - if (supportedByFeatures == null) { - final Set supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, - SupportedFeatures.SUPPORTED_FEATURES); - // If the set of supported features has not been provided, all features are supported by default. - supportedByFeatures = supportedFeatures == null ? Boolean.TRUE - : StmtContextUtils.checkFeatureSupport(this, supportedFeatures); + if (OptionalBoolean.isPresent(supportedByFeatures)) { + return OptionalBoolean.get(supportedByFeatures); } - return supportedByFeatures.booleanValue(); + // If the set of supported features has not been provided, all features are supported by default. + final Set supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, + SupportedFeatures.SUPPORTED_FEATURES); + final boolean ret = supportedFeatures == null ? true + : StmtContextUtils.checkFeatureSupport(this, supportedFeatures); + + supportedByFeatures = OptionalBoolean.of(ret); + return ret; + } @Override diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/DeviateEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/DeviateEffectiveStatementImpl.java index 40cc4263cb..70bf0ccae6 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/DeviateEffectiveStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/DeviateEffectiveStatementImpl.java @@ -12,6 +12,7 @@ import com.google.common.collect.ImmutableSet; import java.util.Collection; import java.util.Objects; import java.util.Set; +import org.opendaylight.yangtools.util.OptionalBoolean; import org.opendaylight.yangtools.yang.model.api.DeviateDefinition; import org.opendaylight.yangtools.yang.model.api.DeviateKind; import org.opendaylight.yangtools.yang.model.api.MustDefinition; @@ -26,9 +27,7 @@ public final class DeviateEffectiveStatementImpl extends DeclaredEffectiveStatementBase implements DeviateDefinition { private final DeviateKind deviateType; - private final Boolean deviatedConfig; private final String deviatedDefault; - private final Boolean deviatedMandatory; private final Integer deviatedMaxElements; private final Integer deviatedMinElements; private final Set deviatedMustDefinitions; @@ -36,6 +35,8 @@ public final class DeviateEffectiveStatementImpl private final Collection deviatedUniqueConstraints; private final String deviatedUnits; + private final byte deviatedConfig; + private final byte deviatedMandatory; public DeviateEffectiveStatementImpl(final StmtContext ctx) { super(ctx); @@ -43,11 +44,11 @@ public final class DeviateEffectiveStatementImpl this.deviateType = argument(); final ConfigEffectiveStatement configStmt = firstEffective(ConfigEffectiveStatement.class); - this.deviatedConfig = configStmt == null ? null : configStmt.argument(); + this.deviatedConfig = OptionalBoolean.ofNullable(configStmt == null ? null : configStmt.argument()); final DefaultEffectiveStatementImpl defaultStmt = firstEffective(DefaultEffectiveStatementImpl.class); this.deviatedDefault = defaultStmt == null ? null : defaultStmt.argument(); final MandatoryEffectiveStatement mandatoryStmt = firstEffective(MandatoryEffectiveStatement.class); - this.deviatedMandatory = mandatoryStmt == null ? null : mandatoryStmt.argument(); + this.deviatedMandatory = OptionalBoolean.ofNullable(mandatoryStmt == null ? null : mandatoryStmt.argument()); final MaxElementsEffectiveStatementImpl maxElementsStmt = firstEffective(MaxElementsEffectiveStatementImpl.class); this.deviatedMaxElements = maxElementsStmt == null ? null : Integer.valueOf(maxElementsStmt.argument()); final MinElementsEffectiveStatementImpl minElementsStmt = firstEffective(MinElementsEffectiveStatementImpl.class); @@ -68,7 +69,7 @@ public final class DeviateEffectiveStatementImpl @Override public Boolean getDeviatedConfig() { - return deviatedConfig; + return OptionalBoolean.toNullable(deviatedConfig); } @Override @@ -78,7 +79,7 @@ public final class DeviateEffectiveStatementImpl @Override public Boolean getDeviatedMandatory() { - return deviatedMandatory; + return OptionalBoolean.toNullable(deviatedMandatory); } @Override @@ -124,9 +125,9 @@ public final class DeviateEffectiveStatementImpl } DeviateEffectiveStatementImpl other = (DeviateEffectiveStatementImpl) obj; return Objects.equals(deviateType, other.deviateType) && - Objects.equals(deviatedConfig, other.deviatedConfig) && + deviatedConfig == other.deviatedConfig && Objects.equals(deviatedDefault, other.deviatedDefault) && - Objects.equals(deviatedMandatory, other.deviatedMandatory) && + deviatedMandatory == other.deviatedMandatory && Objects.equals(deviatedMaxElements, other.deviatedMaxElements) && Objects.equals(deviatedMinElements, other.deviatedMinElements) && Objects.equals(deviatedMustDefinitions, other.deviatedMustDefinitions) &&