Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quantity.fromNumericalAmount, the inverse of getNumericalAmount #5052

Merged
merged 13 commits into from
Apr 28, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Fix #4975: exposing scale operations for all Resources
* Fix #4992: Optimize Quantity parsing to avoid regex overhead
* Fix #4998: removing the internal usage of the Serialization yaml mapper
* Fix #5052: add Quantity.fromNumericalAmount, the inverse of getNumericalAmount

#### Dependency Upgrade
* Fix #5006: Bump BouncyCastle to 1.72
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void setFormat(String format) {
* If this is a memory Quantity, the result will represent bytes.<br>
* If this is a cpu Quantity, the result will represent cores.
*
* @return the formated amount as a number
* @return the formatted amount as a number
* @throws ArithmeticException
*/
@JsonIgnore
Expand Down Expand Up @@ -145,13 +145,39 @@ public static BigDecimal getAmountInBytes(Quantity quantity) throws ArithmeticEx

Quantity amountFormatPair = parse(value);
String formatStr = amountFormatPair.getFormat();

BigDecimal digit = new BigDecimal(amountFormatPair.getAmount());
BigDecimal multiple = getMultiple(formatStr);

return digit.multiply(multiple);
}

/**
* Constructs a new Quantity from the provided amountInBytes. This amount is converted
* to a value with the unit provided in desiredFormat.
*
* @param amountInBytes
* @param desiredFormat
* @see #getNumericalAmount()
* @return a new Quantity with the value of amountInBytes with units desiredFormat
*/
public static Quantity fromNumericalAmount(BigDecimal amountInBytes, String desiredFormat) {
if (desiredFormat == null || desiredFormat.isEmpty()) {
return new Quantity(amountInBytes.stripTrailingZeros().toPlainString());
}

BigDecimal scaledToDesiredFormat = amountInBytes.divide(getMultiple(desiredFormat), MathContext.DECIMAL64);

return new Quantity(scaledToDesiredFormat.stripTrailingZeros().toPlainString(), desiredFormat);
}

private static BigDecimal getMultiple(String formatStr) {
// Handle Decimal exponent case
if (containsAtLeastOneDigit(formatStr) && formatStr.length() > 1) {
int exponent = Integer.parseInt(formatStr.substring(1));
return new BigDecimal("10").pow(exponent, MathContext.DECIMAL64).multiply(new BigDecimal(amountFormatPair.getAmount()));
return new BigDecimal("10").pow(exponent, MathContext.DECIMAL64);
}

BigDecimal digit = new BigDecimal(amountFormatPair.getAmount());
BigDecimal multiple = new BigDecimal("1");
BigDecimal binaryFactor = new BigDecimal("2");
BigDecimal decimalFactor = new BigDecimal("10");
Expand Down Expand Up @@ -207,8 +233,7 @@ public static BigDecimal getAmountInBytes(Quantity quantity) throws ArithmeticEx
default:
throw new IllegalArgumentException("Invalid quantity format passed to parse");
}

return digit.multiply(multiple);
return multiple;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.math.BigDecimal;

Expand Down Expand Up @@ -198,4 +200,14 @@ public void testIndexOfUnit() {
assertEquals(4, Quantity.indexOfUnit("123 K"));
assertEquals(4, Quantity.indexOfUnit("123c"));
}

@ParameterizedTest
@ValueSource(strings = {
"129e6", "129e+6", "1234567890", "8Ki", "7Mi", "6Gi", "5Ti", "4Pi", "3Ei", "5n", "4u", "3m",
"9", "8k", "50k", "7M", "6G", "5T", "40T", "300T", "2P", "1E", ".5Mi", "0.5e-1", "1.1E-5" })
@DisplayName("Test fromAmountInBytes method")
void testFromAmountInBytes(String amount) {
Quantity quantity = new Quantity(amount);
assertEquals(quantity, Quantity.fromNumericalAmount(quantity.getNumericalAmount(), quantity.getFormat()));
}
}