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

com.swirlds.common.formatting.UnitFormatter Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.56.6
Show newest version
/*
 * Copyright (C) 2023-2024 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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 com.swirlds.common.formatting;

import static com.swirlds.common.formatting.StringFormattingUtils.commaSeparatedNumber;

import com.swirlds.common.units.Unit;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;

/**
 * This class generates formatted strings for numbers with units.
 */
public class UnitFormatter {

    private boolean abbreviate = true;
    private int decimalPlaces = 1;
    private boolean showUnit = true;
    private boolean showSpaceInBetween = true;
    private UnitFormat unitFormat = UnitFormat.SINGLE_SIMPLIFIED;

    private Long longQuantity;
    private Double doubleQuantity;
    private final Unit unit;

    /**
     * The lowest unit that will be displayed when using the MULTI_SIMPLIFIED format. This value must not be set if
     * a {@link #unitCount} is set.
     */
    private Unit lowestUnit;

    /**
     * The number of units that will be displayed when using the MULTI_SIMPLIFIED format. This value must not be set if
     * a {@link #lowestUnit} is set.
     */
    private int unitCount;

    /**
     * Create a new unit formatter.
     *
     * @param quantity the quantity
     * @param unit     the unit of the quantity
     */
    public UnitFormatter(final long quantity, final Unit unit) {
        setQuantity(quantity);
        this.unit = unit;
    }

    /**
     * Create a new unit formatter.
     *
     * @param quantity the quantity
     * @param unit     the unit of the quantity
     */
    public UnitFormatter(final double quantity, final Unit unit) {
        setQuantity(quantity);
        this.unit = unit;
    }

    /**
     * Create a new unit formatter.
     */
    public UnitFormatter(final Unit unit) {
        setQuantity(0L);
        this.unit = unit;
    }

    /**
     * Set if the value should be simplified to the best unit.
     *
     * @param unitFormat the unit format
     * @return this object
     */
    @NonNull
    public UnitFormatter setUnitFormat(@NonNull final UnitFormat unitFormat) {
        this.unitFormat = unitFormat;
        return this;
    }

    /**
     * Set the quantity.
     *
     * @param quantity the quantity
     * @return this object
     */
    @NonNull
    public UnitFormatter setQuantity(final long quantity) {
        this.doubleQuantity = null;
        this.longQuantity = quantity;
        return this;
    }

    /**
     * Set the quantity.
     *
     * @param quantity the quantity
     * @return this object
     */
    @NonNull
    public UnitFormatter setQuantity(final double quantity) {
        this.longQuantity = null;
        this.doubleQuantity = quantity;
        return this;
    }

    /**
     * Set if the unit should be abbreviated. Default false;
     *
     * @param abbreviate if true then abbreviate the unit
     * @return this object
     */
    @NonNull
    public UnitFormatter setAbbreviate(final boolean abbreviate) {
        this.abbreviate = abbreviate;
        return this;
    }

    /**
     * Set the number of decimal places to show. Default 2.
     *
     * @param decimalPlaces the number of decimal places to show
     * @return this object
     */
    @NonNull
    public UnitFormatter setDecimalPlaces(final int decimalPlaces) {
        this.decimalPlaces = decimalPlaces;
        return this;
    }

    /**
     * Set if the unit should be displayed. Default true.
     *
     * @param showUnit true if the unit should be displayed
     * @return this object
     */
    @NonNull
    public UnitFormatter setShowUnit(final boolean showUnit) {
        this.showUnit = showUnit;
        return this;
    }

    /**
     * Set the lowest unit that will be displayed when using the MULTI_SIMPLIFIED format. This value must not be set if
     * a {@link #unitCount} is set.
     *
     * @param lowestUnit the lowest unit
     * @return this object
     */
    @NonNull
    public UnitFormatter setLowestUnit(@NonNull final Unit lowestUnit) {
        if (unitCount != 0) {
            throw new IllegalArgumentException("unitCount is already set");
        }

        this.lowestUnit = Objects.requireNonNull(lowestUnit);
        return this;
    }

    /**
     * Set the number of units that will be displayed when using the MULTI_SIMPLIFIED format. This value must not be set if
     * a {@link #lowestUnit} is set.
     *
     * @param unitCount the number of units
     * @return this object
     */
    @NonNull
    public UnitFormatter setUnitCount(final int unitCount) {
        if (lowestUnit != null) {
            throw new IllegalArgumentException("lowestUnit is already set");
        }

        this.unitCount = unitCount;
        return this;
    }

    /**
     * Set if there should be a space put in between the number and the unit. Default true.
     *
     * @param showSpaceInBetween true if there should be a space in between the number and the unit
     * @return this object
     */
    @NonNull
    public UnitFormatter setShowSpaceInBetween(final boolean showSpaceInBetween) {
        this.showSpaceInBetween = showSpaceInBetween;
        return this;
    }

    /**
     * Render the number as a string.
     *
     * @return the rendered string
     */
    @NonNull
    public String render() {
        final StringBuilder sb = new StringBuilder();
        render(sb);
        return sb.toString();
    }

    /**
     * Checks whether the given quantity string requires a plural unit
     * 

* Any number other than 1.0 is considered to be plural. * * @param quantityString the quantity string * @return true if the quantity string requires a plural unit */ private boolean isQuantityPlural(@NonNull final String quantityString) { return Double.parseDouble(quantityString.replace(",", "")) != 1.0; } /** * Append the unit to the string builder. * * @param stringBuilder the string builder to append to * @param quantityString the quantity string * @param finalUnit the unit to append */ private void appendUnit( @NonNull final StringBuilder stringBuilder, @NonNull final String quantityString, @NonNull final Unit finalUnit) { if (showSpaceInBetween) { stringBuilder.append(" "); } if (abbreviate) { stringBuilder.append(finalUnit.getAbbreviation()); } else { if (isQuantityPlural(quantityString)) { stringBuilder.append(finalUnit.getPluralName()); } else { stringBuilder.append(finalUnit.getName()); } } } /** * Format the number with no unit simplification. The printed unit will be the original unit * * @param stringBuilder the string builder to write the rendered string to */ private void formatWithUnsimplifiedUnit(@NonNull final StringBuilder stringBuilder) { final double quantity = longQuantity == null ? doubleQuantity : (double) longQuantity; final String quantityString = commaSeparatedNumber(quantity, decimalPlaces); stringBuilder.append(quantityString); if (showUnit) { appendUnit(stringBuilder, quantityString, unit); } } /** * Format the number with a single simplified unit * * @param stringBuilder the string builder to write the rendered string to */ private void formatWithSingleSimplifiedUnit(@NonNull final StringBuilder stringBuilder) { final Unit.SimplifiedQuantity simplifiedQuantity; if (longQuantity == null) { simplifiedQuantity = unit.simplify(doubleQuantity); } else { simplifiedQuantity = unit.simplify(longQuantity); } final String quantityString = commaSeparatedNumber(simplifiedQuantity.quantity(), decimalPlaces); stringBuilder.append(quantityString); if (showUnit) { appendUnit(stringBuilder, quantityString, simplifiedQuantity.unit()); } } /** * Add a term to the string builder, and return the remainder * * @param stringBuilder the string builder to write the rendered string to * @param startingQuantity the starting quantity * @param finalUnitOrdinal the lowest unit ordinal that may be displayed * @return the remainder */ @NonNull private Unit.SimplifiedQuantity addTerm( @NonNull final StringBuilder stringBuilder, @NonNull final Unit.SimplifiedQuantity startingQuantity, int finalUnitOrdinal) { final long roundedDownQuantity = (long) startingQuantity.quantity(); final Unit.SimplifiedQuantity remainder = new Unit.SimplifiedQuantity<>( startingQuantity.quantity() - roundedDownQuantity, startingQuantity.unit()); final Unit.SimplifiedQuantity simplifiedRemainder = remainder.unit().simplify(remainder.quantity()); final String termString; if (simplifiedRemainder.unit().ordinal() < finalUnitOrdinal) { termString = commaSeparatedNumber(startingQuantity.quantity(), decimalPlaces); } else { termString = commaSeparatedNumber(roundedDownQuantity, 0); } stringBuilder.append(termString); // multi simplified format always displays the unit appendUnit(stringBuilder, termString, startingQuantity.unit()); return simplifiedRemainder; } /** * Format the number with multiple units. * * @param stringBuilder the string builder to write the rendered string to */ private void formatWithMultiSimplifiedUnits(@NonNull final StringBuilder stringBuilder) { double originalQuantity = longQuantity == null ? doubleQuantity : (double) longQuantity; final Unit.SimplifiedQuantity firstTerm = new Unit.SimplifiedQuantity<>(originalQuantity, unit).unit().simplify(originalQuantity); final int finalUnitOrdinal; if (lowestUnit != null) { finalUnitOrdinal = lowestUnit.ordinal(); } else if (unitCount != 0) { finalUnitOrdinal = Math.max(0, firstTerm.unit().ordinal() - unitCount + 1); } else { finalUnitOrdinal = unit.ordinal(); } Unit.SimplifiedQuantity remainder = addTerm(stringBuilder, firstTerm, finalUnitOrdinal); while (remainder.unit().ordinal() >= finalUnitOrdinal) { stringBuilder.append(" "); remainder = addTerm(stringBuilder, remainder, finalUnitOrdinal); } } /** * Render the number and write it to a string builder * * @param stringBuilder the string builder to write the rendered string to */ public void render(@NonNull final StringBuilder stringBuilder) { Objects.requireNonNull(stringBuilder); if (longQuantity == null && doubleQuantity == null) { throw new IllegalStateException("Quantity must be set"); } if (longQuantity != null && doubleQuantity != null) { throw new IllegalStateException("Quantity must be set to either long or double, not both"); } switch (unitFormat) { case UNSIMPLIFIED -> formatWithUnsimplifiedUnit(stringBuilder); case SINGLE_SIMPLIFIED -> formatWithSingleSimplifiedUnit(stringBuilder); case MULTI_SIMPLIFIED -> formatWithMultiSimplifiedUnits(stringBuilder); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy