All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.smithy.model.node.NumberNode Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package software.amazon.smithy.model.node;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import software.amazon.smithy.model.SourceLocation;

/**
 * Represents a number node. Number nodes contain a {@code Number} value.
 *
 * 

Number nodes contain a value. You can inspect its type by calling * {@code isNaturalNumber()} or {@code isFloatingPointNumber()}. Natural * numbers are positive, or negative numbers without a decimal part. */ public final class NumberNode extends Node { private final BigDecimal value; private final Number originalValue; private final String stringCache; private boolean isNaN; private boolean isPositiveInfinity; private boolean isNegativeInfinity; public NumberNode(Number value, SourceLocation sourceLocation) { super(sourceLocation); originalValue = value; stringCache = value.toString(); this.value = toBigDecimal(originalValue); } private BigDecimal toBigDecimal(Number value) { if (value instanceof BigDecimal) { return (BigDecimal) value; } else if (value instanceof Integer || value instanceof Long || value instanceof Short || value instanceof Byte) { return BigDecimal.valueOf(value.longValue()); } else if (value instanceof Float || value instanceof Double) { double d = value.doubleValue(); if (Double.isNaN(d)) { isNaN = true; return null; } else if (Double.isInfinite(d)) { if (stringCache.startsWith("-")) { isNegativeInfinity = true; } else { isPositiveInfinity = true; } return null; } else { return BigDecimal.valueOf(d); } } else if (value instanceof BigInteger) { return new BigDecimal((BigInteger) value); } else { return new BigDecimal(stringCache); } } /** * Gets the number value. * * @return Returns a number. */ public Number getValue() { return originalValue; } /** * Gets the number value as a BigDecimal if possible. * *

NaN and infinite numbers will return an empty Optional. * * @return Returns the BigDecimal value of the wrapped number. */ public Optional asBigDecimal() { return Optional.ofNullable(value); } @Deprecated public boolean isNaturalNumber() { return !isFloatingPointNumber(); } /** * Check the value is negative, including negative infinity. * *

Any number >= 0, +Infinity, and NaN return false. * * @return Return true if negative. */ public boolean isNegative() { return isNegativeInfinity || (value != null && value.compareTo(BigDecimal.ZERO) < 0); } /** * Returns true if the node contains a floating point number. * * @return Returns true if the node contains a floating point number. */ public boolean isFloatingPointNumber() { return value == null || value.scale() > 0 || toString().contains("."); } /** * Returns true if the number is a floating point NaN. * * @return Return true if NaN. */ public boolean isNaN() { return isNaN; } /** * Returns true if the number is infinite. * * @return Return true if infinite. */ public boolean isInfinite() { return isPositiveInfinity || isNegativeInfinity; } @Override public NodeType getType() { return NodeType.NUMBER; } @Override public R accept(NodeVisitor visitor) { return visitor.numberNode(this); } @Override public NumberNode expectNumberNode(String errorMessage) { return this; } @Override public NumberNode expectNumberNode(Supplier errorMessage) { return this; } @Override public Optional asNumberNode() { return Optional.of(this); } /** * Returns true if the value of the number contained in the number node is zero, * accounting for float, double, bigInteger, bigDecimal, and other numeric types * (e.g., 0, 0.0, etc). * *

Note that -0 and +0 are considered 0. However, NaN is not considered zero. * When unknown number types are encountered, this method will return true if the * toString of the given number returns "0", or "0.0". Other kinds of unknown * number types will be treated like a double. * *

Double and float comparisons to zero are exact and use no rounding. The majority * of values seen by this method come from models that use "0" or "0.0". However, * we can improve this in the future with some kind of epsilon if the need arises. * * @return Returns true if set to zero. */ public boolean isZero() { return value != null && value.compareTo(BigDecimal.ZERO) == 0; } @Override public boolean equals(Object other) { if (!(other instanceof NumberNode)) { return false; } else if (other == this) { return true; } else { NumberNode o = (NumberNode) other; return isNaN == o.isNaN && isPositiveInfinity == o.isPositiveInfinity && isNegativeInfinity == o.isNegativeInfinity && Objects.equals(value, o.value); } } @Override public int hashCode() { return getType().hashCode() * 7 + stringCache.hashCode(); } @Override public String toString() { return stringCache; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy