mirror of
https://github.com/lightbend/config.git
synced 2025-02-21 08:40:51 +08:00
Improve size-in-bytes parser's use of BigInteger/BigDecimal
- use bitLength to see if we overflow Long - use BigInteger and BigDecimal to parse, instead of parseLong/parseDouble
This commit is contained in:
parent
6311ef8d4d
commit
02867c8aec
@ -624,12 +624,6 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidLong(BigInteger v) {
|
||||
BigInteger max = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
BigInteger min = BigInteger.valueOf(Long.MIN_VALUE);
|
||||
return max.compareTo(v) >= 0 && min.compareTo(v) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a size-in-bytes string. If no units are specified in the string,
|
||||
* it is assumed to be in bytes. The returned value is in bytes. The purpose
|
||||
@ -673,14 +667,12 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
|
||||
// if the string is purely digits, parse as an integer to avoid
|
||||
// possible precision loss; otherwise as a double.
|
||||
if (numberString.matches("[0-9]+")) {
|
||||
Long v = Long.parseLong(numberString);
|
||||
result = units.bytes.multiply(BigInteger.valueOf(v));
|
||||
result = units.bytes.multiply(new BigInteger(numberString));
|
||||
} else {
|
||||
Double v = Double.parseDouble(numberString);
|
||||
BigDecimal resultDecimal = (new BigDecimal(units.bytes)).multiply(BigDecimal.valueOf(v));
|
||||
BigDecimal resultDecimal = (new BigDecimal(units.bytes)).multiply(new BigDecimal(numberString));
|
||||
result = resultDecimal.toBigInteger();
|
||||
}
|
||||
if (isValidLong(result))
|
||||
if (result.bitLength() < 64)
|
||||
return result.longValue();
|
||||
else
|
||||
throw new ConfigException.BadValue(originForException, pathForException,
|
||||
|
@ -59,7 +59,10 @@ class UnitParserTest extends TestUtils {
|
||||
|
||||
@Test
|
||||
def parseMemorySizeInBytes(): Unit = {
|
||||
def parseMem(s: String) = SimpleConfig.parseBytes(s, fakeOrigin(), "test")
|
||||
def parseMem(s: String): Long = SimpleConfig.parseBytes(s, fakeOrigin(), "test")
|
||||
|
||||
assertEquals(Long.MaxValue, parseMem(s"${Long.MaxValue} bytes"))
|
||||
assertEquals(Long.MinValue, parseMem(s"${Long.MinValue} bytes"))
|
||||
|
||||
val oneMebis = List("1048576", "1048576b", "1048576bytes", "1048576byte",
|
||||
"1048576 b", "1048576 bytes",
|
||||
@ -123,13 +126,18 @@ class UnitParserTest extends TestUtils {
|
||||
// later on we'll want to check this with BigInteger version of getBytes
|
||||
@Test
|
||||
def parseHugeMemorySizes(): Unit = {
|
||||
def parseMem(s: String) = SimpleConfig.parseBytes(s, fakeOrigin(), "test")
|
||||
def parseMem(s: String): Long = SimpleConfig.parseBytes(s, fakeOrigin(), "test")
|
||||
def assertOutOfRange(s: String) = {
|
||||
val fail = intercept[ConfigException.BadValue] {
|
||||
parseMem(s)
|
||||
}
|
||||
assertTrue("number was too big", fail.getMessage.contains("out of range"))
|
||||
}
|
||||
|
||||
import java.math.BigInteger
|
||||
assertOutOfRange(s"${BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(1)).toString} bytes")
|
||||
assertOutOfRange(s"${BigInteger.valueOf(Long.MinValue).subtract(BigInteger.valueOf(1)).toString} bytes")
|
||||
|
||||
var result = 1024L * 1024 * 1024
|
||||
for (unit <- Seq("zebi", "yobi")) {
|
||||
val first = unit.substring(0, 1).toUpperCase()
|
||||
|
Loading…
Reference in New Issue
Block a user