mirror of
https://github.com/lightbend/config.git
synced 2025-02-23 01:30:34 +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,
|
* 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
|
* 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
|
// if the string is purely digits, parse as an integer to avoid
|
||||||
// possible precision loss; otherwise as a double.
|
// possible precision loss; otherwise as a double.
|
||||||
if (numberString.matches("[0-9]+")) {
|
if (numberString.matches("[0-9]+")) {
|
||||||
Long v = Long.parseLong(numberString);
|
result = units.bytes.multiply(new BigInteger(numberString));
|
||||||
result = units.bytes.multiply(BigInteger.valueOf(v));
|
|
||||||
} else {
|
} else {
|
||||||
Double v = Double.parseDouble(numberString);
|
BigDecimal resultDecimal = (new BigDecimal(units.bytes)).multiply(new BigDecimal(numberString));
|
||||||
BigDecimal resultDecimal = (new BigDecimal(units.bytes)).multiply(BigDecimal.valueOf(v));
|
|
||||||
result = resultDecimal.toBigInteger();
|
result = resultDecimal.toBigInteger();
|
||||||
}
|
}
|
||||||
if (isValidLong(result))
|
if (result.bitLength() < 64)
|
||||||
return result.longValue();
|
return result.longValue();
|
||||||
else
|
else
|
||||||
throw new ConfigException.BadValue(originForException, pathForException,
|
throw new ConfigException.BadValue(originForException, pathForException,
|
||||||
|
@ -59,7 +59,10 @@ class UnitParserTest extends TestUtils {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
def parseMemorySizeInBytes(): Unit = {
|
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",
|
val oneMebis = List("1048576", "1048576b", "1048576bytes", "1048576byte",
|
||||||
"1048576 b", "1048576 bytes",
|
"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
|
// later on we'll want to check this with BigInteger version of getBytes
|
||||||
@Test
|
@Test
|
||||||
def parseHugeMemorySizes(): Unit = {
|
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) = {
|
def assertOutOfRange(s: String) = {
|
||||||
val fail = intercept[ConfigException.BadValue] {
|
val fail = intercept[ConfigException.BadValue] {
|
||||||
parseMem(s)
|
parseMem(s)
|
||||||
}
|
}
|
||||||
assertTrue("number was too big", fail.getMessage.contains("out of range"))
|
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
|
var result = 1024L * 1024 * 1024
|
||||||
for (unit <- Seq("zebi", "yobi")) {
|
for (unit <- Seq("zebi", "yobi")) {
|
||||||
val first = unit.substring(0, 1).toUpperCase()
|
val first = unit.substring(0, 1).toUpperCase()
|
||||||
|
Loading…
Reference in New Issue
Block a user