mirror of
https://github.com/lightbend/config.git
synced 2025-01-28 21:20:07 +08:00
Convert numbers to ConfigInt when possible, then ConfigLong, and ConfigDouble only when required
Had to overhaul and clean up equality of ConfigNumber as part of this.
This commit is contained in:
parent
054e27ccd0
commit
61b1281e90
@ -5,7 +5,7 @@ import com.typesafe.config.ConfigResolveOptions;
|
||||
import com.typesafe.config.ConfigValue;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Trying very hard to avoid a parent reference in config values; when you have
|
||||
* a tree like this, the availability of parent() tends to result in a lot of
|
||||
* improperly-factored and non-modular code. Please don't add parent().
|
||||
@ -121,4 +121,22 @@ abstract class AbstractConfigValue implements ConfigValue {
|
||||
String transformToString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
static ConfigNumber newNumber(ConfigOrigin origin, long number,
|
||||
String originalText) {
|
||||
if (number <= Integer.MAX_VALUE && number >= Integer.MIN_VALUE)
|
||||
return new ConfigInt(origin, (int) number, originalText);
|
||||
else
|
||||
return new ConfigLong(origin, number, originalText);
|
||||
}
|
||||
|
||||
static ConfigNumber newNumber(ConfigOrigin origin, double number,
|
||||
String originalText) {
|
||||
long asLong = (long) number;
|
||||
if (asLong == number) {
|
||||
return newNumber(origin, asLong, originalText);
|
||||
} else {
|
||||
return new ConfigDouble(origin, number, originalText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,4 +30,14 @@ final class ConfigDouble extends ConfigNumber {
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long longValue() {
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -22,30 +22,6 @@ final class ConfigInt extends ConfigNumber {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canEqual(Object other) {
|
||||
return other instanceof ConfigInt || other instanceof ConfigLong;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
if (other instanceof ConfigInt) {
|
||||
return this.value == ((ConfigInt) other).value;
|
||||
} else if (other instanceof ConfigLong) {
|
||||
Long l = ((ConfigLong) other).unwrapped();
|
||||
return l.intValue() == l && this.value == l.intValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
String transformToString() {
|
||||
String s = super.transformToString();
|
||||
@ -54,4 +30,14 @@ final class ConfigInt extends ConfigNumber {
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long longValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -22,35 +22,6 @@ final class ConfigLong extends ConfigNumber {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canEqual(Object other) {
|
||||
return other instanceof ConfigInt || other instanceof ConfigLong;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
if (other instanceof ConfigLong) {
|
||||
return this.value == ((ConfigLong) other).value;
|
||||
} else if (other instanceof ConfigInt) {
|
||||
Long l = this.unwrapped();
|
||||
return l.intValue() == l
|
||||
&& ((ConfigInt) other).unwrapped() == l.intValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE)
|
||||
return unwrapped().intValue(); // match the ConfigInt hashCode for
|
||||
// any valid Integer
|
||||
else
|
||||
return unwrapped().hashCode(); // use Long.hashCode()
|
||||
}
|
||||
|
||||
@Override
|
||||
String transformToString() {
|
||||
String s = super.transformToString();
|
||||
@ -59,4 +30,14 @@ final class ConfigLong extends ConfigNumber {
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long longValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -18,4 +18,48 @@ abstract class ConfigNumber extends AbstractConfigValue {
|
||||
String transformToString() {
|
||||
return originalText;
|
||||
}
|
||||
|
||||
protected abstract long longValue();
|
||||
|
||||
protected abstract double doubleValue();
|
||||
|
||||
private boolean isWhole() {
|
||||
long asLong = longValue();
|
||||
return asLong == doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canEqual(Object other) {
|
||||
return other instanceof ConfigNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
if (canEqual(other)) {
|
||||
ConfigNumber n = (ConfigNumber) other;
|
||||
if (isWhole()) {
|
||||
return n.isWhole() && this.longValue() == n.longValue();
|
||||
} else {
|
||||
return (!n.isWhole()) && this.doubleValue() == n.doubleValue();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
|
||||
// this matches what standard Long.hashCode and Double.hashCode
|
||||
// do, though I don't think it really matters.
|
||||
long asLong;
|
||||
if (isWhole()) {
|
||||
asLong = longValue();
|
||||
} else {
|
||||
asLong = Double.doubleToLongBits(doubleValue());
|
||||
}
|
||||
return (int) (asLong ^ (asLong >>> 32));
|
||||
}
|
||||
}
|
||||
|
@ -265,16 +265,19 @@ final class Tokens {
|
||||
}
|
||||
|
||||
static Token newInt(ConfigOrigin origin, int value, String originalText) {
|
||||
return newValue(new ConfigInt(origin, value, originalText));
|
||||
return newValue(AbstractConfigValue.newNumber(origin, value,
|
||||
originalText));
|
||||
}
|
||||
|
||||
static Token newDouble(ConfigOrigin origin, double value,
|
||||
String originalText) {
|
||||
return newValue(new ConfigDouble(origin, value, originalText));
|
||||
return newValue(AbstractConfigValue.newNumber(origin, value,
|
||||
originalText));
|
||||
}
|
||||
|
||||
static Token newLong(ConfigOrigin origin, long value, String originalText) {
|
||||
return newValue(new ConfigLong(origin, value, originalText));
|
||||
return newValue(AbstractConfigValue.newNumber(origin, value,
|
||||
originalText));
|
||||
}
|
||||
|
||||
static Token newNull(ConfigOrigin origin) {
|
||||
|
@ -404,7 +404,7 @@ class ConfigTest extends TestUtils {
|
||||
assertEquals(stringValue("abcd"), conf.getValue("strings.abcd"))
|
||||
|
||||
// get stuff with getAny
|
||||
assertEquals(42L, conf.getAnyRef("ints.fortyTwo"))
|
||||
assertEquals(42, conf.getAnyRef("ints.fortyTwo"))
|
||||
assertEquals("abcd", conf.getAnyRef("strings.abcd"))
|
||||
assertEquals(false, conf.getAnyRef("booleans.falseAgain"))
|
||||
|
||||
|
@ -405,4 +405,21 @@ class ConfigValueTest extends TestUtils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
def newNumberWorks() {
|
||||
def nL(v: Long) = AbstractConfigValue.newNumber(fakeOrigin(), v, null)
|
||||
def nD(v: Double) = AbstractConfigValue.newNumber(fakeOrigin(), v, null)
|
||||
|
||||
// the general idea is that the destination type should depend
|
||||
// only on the actual numeric value, not on the type of the source
|
||||
// value.
|
||||
assertEquals(3.14, nD(3.14).unwrapped())
|
||||
assertEquals(1, nL(1).unwrapped())
|
||||
assertEquals(1, nD(1.0).unwrapped())
|
||||
assertEquals(Int.MaxValue + 1L, nL(Int.MaxValue + 1L).unwrapped())
|
||||
assertEquals(Int.MinValue - 1L, nL(Int.MinValue - 1L).unwrapped())
|
||||
assertEquals(Int.MaxValue + 1L, nD(Int.MaxValue + 1.0).unwrapped())
|
||||
assertEquals(Int.MinValue - 1L, nD(Int.MinValue - 1.0).unwrapped())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user