From 879a082d90ce368b344c6e9bb48cbf2f1b2a9e3b Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 14 Mar 2022 00:55:26 +0100 Subject: [PATCH] Improve Decimal64 range support We have classImporter available during generation, hence we can neatly import Decimal64, reducing boiler plate in range and value declarations. Decimal64 also exposes a fast instantiation type with scale and unscaled value -- use those instead of parsing strings. Change-Id: Ieba07af36fa3d03e20fda0c65754ec2dbfeee451 Signed-off-by: Robert Varga --- .../generator/AbstractBigRangeGenerator.java | 86 ------------------- .../AbstractPrimitiveRangeGenerator.java | 11 ++- .../api/generator/AbstractRangeGenerator.java | 9 -- .../generator/Decimal64RangeGenerator.java | 76 +++++++++++++++- .../api/generator/LongRangeGenerator.java | 3 +- .../Decimal64RangeGeneratorTest.java | 2 - 6 files changed, 83 insertions(+), 104 deletions(-) delete mode 100644 binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractBigRangeGenerator.java diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractBigRangeGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractBigRangeGenerator.java deleted file mode 100644 index 4a47616358..0000000000 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractBigRangeGenerator.java +++ /dev/null @@ -1,86 +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.mdsal.binding.java.api.generator; - -import com.google.common.collect.Range; -import java.lang.reflect.Array; -import java.util.Locale; -import java.util.Set; -import java.util.function.Function; -import org.opendaylight.yangtools.yang.binding.CodeHelpers; -import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; - -/** - * Abstract base for generators which require instantiation of boundary values to check. These are implemented - * by generating an array constant within the class, which contains {@link Range} instances, which hold pre-instantiated - * boundary values. - * - * @param type of the class - */ -abstract class AbstractBigRangeGenerator> extends AbstractRangeGenerator { - protected AbstractBigRangeGenerator(final Class typeClass) { - super(typeClass); - } - - private static String range(final Function, String> classImporter) { - return classImporter.apply(Range.class); - } - - private String itemType(final Function, String> classImporter) { - return range(classImporter) + '<' + getTypeName() + '>'; - } - - private String arrayType(final Function, String> classImporter) { - return itemType(classImporter) + "[]"; - } - - @Override - protected final String generateRangeCheckerImplementation(final String checkerName, - final RangeConstraint constraint, final Function, String> classImporter) { - final Set> constraints = constraint.getAllowedRanges().asRanges(); - final String fieldName = checkerName.toUpperCase(Locale.ENGLISH) + "_RANGES"; - final StringBuilder sb = new StringBuilder(); - - // Field to hold the Range objects in an array - sb.append("private static final ").append(arrayType(classImporter)).append(' ').append(fieldName).append(";\n"); - - // Static initializer block for the array - sb.append("static {\n"); - sb.append(" @SuppressWarnings(\"unchecked\")\n"); - sb.append(" final ").append(arrayType(classImporter)).append(" a = (").append(arrayType(classImporter)) - .append(") ").append(classImporter.apply(Array.class)).append(".newInstance(").append(range(classImporter)) - .append(".class, ").append(constraints.size()).append(");\n"); - - int offset = 0; - for (Range r : constraints) { - final String min = format(getValue(r.lowerEndpoint())); - final String max = format(getValue(r.upperEndpoint())); - - sb.append(" a[").append(offset++).append("] = ").append(range(classImporter)).append(".closed(") - .append(min).append(", ").append(max).append(");\n"); - } - - sb.append(" ").append(fieldName).append(" = a;\n"); - sb.append("}\n"); - - // Static enforcement method - sb.append("private static void ").append(checkerName).append("(final ").append(getTypeName()) - .append(" value) {\n"); - sb.append(" for (").append(itemType(classImporter)).append(" r : ").append(fieldName).append(") {\n"); - sb.append(" if (r.contains(value)) {\n"); - sb.append(" return;\n"); - sb.append(" }\n"); - sb.append(" }\n"); - - sb.append(" ").append(classImporter.apply(CodeHelpers.class)).append(".throwInvalidRange(").append(fieldName) - .append(", value);\n"); - sb.append("}\n"); - - return sb.toString(); - } -} diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractPrimitiveRangeGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractPrimitiveRangeGenerator.java index 0c8fe8e9e4..e29a9a16be 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractPrimitiveRangeGenerator.java +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractPrimitiveRangeGenerator.java @@ -27,7 +27,7 @@ abstract class AbstractPrimitiveRangeGenerator> private final @NonNull T minValue; private final @NonNull T maxValue; - protected AbstractPrimitiveRangeGenerator(final Class typeClass, final String primitiveName, final T minValue, + AbstractPrimitiveRangeGenerator(final Class typeClass, final String primitiveName, final T minValue, final T maxValue) { super(typeClass); this.primitiveName = requireNonNull(primitiveName); @@ -94,6 +94,15 @@ abstract class AbstractPrimitiveRangeGenerator> sb.append("value >= ").append(format(min)); } + /** + * Format a value into a Java-compilable expression which results in the appropriate + * type. + * + * @param value Number value + * @return Java language string representation + */ + protected abstract @NonNull String format(T value); + String codeHelpersThrow() { return "throwInvalidRange"; } diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractRangeGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractRangeGenerator.java index 27c580f9af..50e9798df8 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractRangeGenerator.java +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractRangeGenerator.java @@ -105,15 +105,6 @@ abstract class AbstractRangeGenerator> { @Deprecated protected abstract T convert(Number value); - /** - * Format a value into a Java-compilable expression which results in the appropriate - * type. - * - * @param value Number value - * @return Java language string representation - */ - protected abstract @NonNull String format(T value); - /** * Generate the checker method source code. * @param checkerName Name of the checker method. diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGenerator.java index dcb6497a1e..93342e7096 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGenerator.java +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGenerator.java @@ -7,18 +7,41 @@ */ package org.opendaylight.mdsal.binding.java.api.generator; +import com.google.common.collect.Range; +import java.lang.reflect.Array; +import java.util.Locale; +import java.util.Set; +import java.util.function.Function; +import org.opendaylight.yangtools.yang.binding.CodeHelpers; import org.opendaylight.yangtools.yang.common.Decimal64; import org.opendaylight.yangtools.yang.common.Uint16; import org.opendaylight.yangtools.yang.common.Uint8; +import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint; -final class Decimal64RangeGenerator extends AbstractBigRangeGenerator { +/** + * Decimal64 boundary check generator. It requires instantiation of boundary values -- these are implemented by + * generating an array constant within the class, which contains {@link Range} instances, which hold pre-instantiated + * boundary values. + */ +final class Decimal64RangeGenerator extends AbstractRangeGenerator { Decimal64RangeGenerator() { super(Decimal64.class); } - @Override - protected String format(final Decimal64 value) { - return "org.opendaylight.yangtools.yang.common.Decimal64.valueOf(\"" + value + "\")"; + private static String range(final Function, String> classImporter) { + return classImporter.apply(Range.class); + } + + private static String itemType(final Function, String> classImporter) { + return range(classImporter) + '<' + classImporter.apply(Decimal64.class) + '>'; + } + + private static String arrayType(final Function, String> classImporter) { + return itemType(classImporter) + "[]"; + } + + private static String format(final Function, String> classImporter, final Decimal64 value) { + return classImporter.apply(Decimal64.class) + ".of(" + value.scale() + ", " + value.unscaledValue() + "L)"; } @Override @@ -33,4 +56,49 @@ final class Decimal64RangeGenerator extends AbstractBigRangeGenerator return Decimal64.valueOf(1, value.longValue()); } } + + @Override + protected String generateRangeCheckerImplementation(final String checkerName, + final RangeConstraint constraint, final Function, String> classImporter) { + final Set> constraints = constraint.getAllowedRanges().asRanges(); + final String fieldName = checkerName.toUpperCase(Locale.ENGLISH) + "_RANGES"; + final StringBuilder sb = new StringBuilder(); + + // Field to hold the Range objects in an array + sb.append("private static final ").append(arrayType(classImporter)).append(' ').append(fieldName).append(";\n"); + + // Static initializer block for the array + sb.append("static {\n"); + sb.append(" @SuppressWarnings(\"unchecked\")\n"); + sb.append(" final ").append(arrayType(classImporter)).append(" a = (").append(arrayType(classImporter)) + .append(") ").append(classImporter.apply(Array.class)).append(".newInstance(").append(range(classImporter)) + .append(".class, ").append(constraints.size()).append(");\n"); + + int offset = 0; + for (Range r : constraints) { + final String min = format(classImporter, getValue(r.lowerEndpoint())); + final String max = format(classImporter, getValue(r.upperEndpoint())); + + sb.append(" a[").append(offset++).append("] = ").append(range(classImporter)).append(".closed(") + .append(min).append(", ").append(max).append(");\n"); + } + + sb.append(" ").append(fieldName).append(" = a;\n"); + sb.append("}\n"); + + // Static enforcement method + sb.append("private static void ").append(checkerName).append("(final ").append(getTypeName()) + .append(" value) {\n"); + sb.append(" for (").append(itemType(classImporter)).append(" r : ").append(fieldName).append(") {\n"); + sb.append(" if (r.contains(value)) {\n"); + sb.append(" return;\n"); + sb.append(" }\n"); + sb.append(" }\n"); + + sb.append(" ").append(classImporter.apply(CodeHelpers.class)).append(".throwInvalidRange(").append(fieldName) + .append(", value);\n"); + sb.append("}\n"); + + return sb.toString(); + } } diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/LongRangeGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/LongRangeGenerator.java index a1c78c89bb..736e052da7 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/LongRangeGenerator.java +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/LongRangeGenerator.java @@ -8,8 +8,7 @@ package org.opendaylight.mdsal.binding.java.api.generator; final class LongRangeGenerator extends AbstractPrimitiveRangeGenerator { - - protected LongRangeGenerator() { + LongRangeGenerator() { super(Long.class, long.class.getName(), Long.MIN_VALUE, Long.MAX_VALUE); } diff --git a/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGeneratorTest.java b/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGeneratorTest.java index 5f96b3ddf5..4fcde3a4a9 100644 --- a/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGeneratorTest.java +++ b/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/Decimal64RangeGeneratorTest.java @@ -8,7 +8,6 @@ package org.opendaylight.mdsal.binding.java.api.generator; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import java.math.BigInteger; import org.junit.Test; @@ -25,6 +24,5 @@ public class Decimal64RangeGeneratorTest { assertEquals(one, generator.convert(Byte.valueOf("1"))); assertEquals(one, generator.convert(Short.valueOf("1"))); assertEquals(one, generator.convert(Integer.valueOf("1"))); - assertNotNull(generator.format(Decimal64.valueOf("10"))); } } -- 2.36.6