Skip to content

Commit

Permalink
Introduce new 'unsigned_long' numeric field type support
Browse files Browse the repository at this point in the history
Signed-off-by: Andriy Redko <andriy.redko@aiven.io>
  • Loading branch information
reta committed Feb 8, 2023
1 parent 1f4cdd2 commit a1fc76e
Show file tree
Hide file tree
Showing 14 changed files with 379 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import java.io.Closeable;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.CharBuffer;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -218,6 +219,8 @@ <T> Map<String, T> map(Supplier<Map<String, T>> mapFactory, CheckedFunction<XCon

double doubleValue(boolean coerce) throws IOException;

BigInteger bigIntegerValue(boolean coerce) throws IOException;

short shortValue() throws IOException;

int intValue() throws IOException;
Expand All @@ -228,6 +231,8 @@ <T> Map<String, T> map(Supplier<Map<String, T>> mapFactory, CheckedFunction<XCon

double doubleValue() throws IOException;

BigInteger bigIntegerValue() throws IOException;

/**
* @return true iff the current value is either boolean (<code>true</code> or <code>false</code>) or one of "false", "true".
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.opensearch.common.CheckedFunction;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.CharBuffer;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -219,7 +220,12 @@ public float floatValue(boolean coerce) throws IOException {

@Override
public double doubleValue(boolean coerce) throws IOException {
return parser.doubleValue();
return parser.doubleValue(coerce);
}

@Override
public BigInteger bigIntegerValue(boolean coerce) throws IOException {
return parser.bigIntegerValue(coerce);
}

@Override
Expand Down Expand Up @@ -247,6 +253,11 @@ public double doubleValue() throws IOException {
return parser.doubleValue();
}

@Override
public BigInteger bigIntegerValue() throws IOException {
return parser.bigIntegerValue();
}

@Override
public boolean isBooleanValue() throws IOException {
return parser.isBooleanValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.opensearch.core.internal.io.IOUtils;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.CharBuffer;

public class JsonXContentParser extends AbstractXContentParser {
Expand Down Expand Up @@ -188,6 +189,11 @@ public double doDoubleValue() throws IOException {
return parser.getDoubleValue();
}

@Override
public BigInteger doBigIntegerValue() throws IOException {
return parser.getBigIntegerValue();
}

@Override
public byte[] binaryValue() throws IOException {
return parser.getBinaryValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,23 @@ public double doubleValue(boolean coerce) throws IOException {

protected abstract double doDoubleValue() throws IOException;

@Override
public BigInteger bigIntegerValue() throws IOException {
return bigIntegerValue(DEFAULT_NUMBER_COERCE_POLICY);
}

@Override
public BigInteger bigIntegerValue(boolean coerce) throws IOException {
Token token = currentToken();
if (token == Token.VALUE_STRING) {
checkCoerceString(coerce, BigInteger.class);
return new BigInteger(text());
}
return doBigIntegerValue();
}

protected abstract BigInteger doBigIntegerValue() throws IOException;

@Override
public final String textOrNull() throws IOException {
if (currentToken() == Token.VALUE_NULL) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ protected double doDoubleValue() throws IOException {
return numberValue().doubleValue();
}

@Override
protected BigInteger doBigIntegerValue() throws IOException {
if (numberValue() instanceof BigInteger) {
return (BigInteger) numberValue();
} else {
return BigInteger.valueOf(numberValue().longValue());
}
}

@Override
public XContentType contentType() {
return xContentType;
Expand Down
65 changes: 65 additions & 0 deletions server/src/main/java/org/opensearch/common/Numbers.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
* @opensearch.internal
*/
public final class Numbers {
public static final BigInteger MAX_UNSIGNED_LONG_VALUE = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE);
public static final BigInteger MIN_UNSIGNED_LONG_VALUE = BigInteger.ZERO;
public static final int UNSIGNED_LONG_BYTES = 8;

private static final BigInteger MAX_LONG_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
private static final BigInteger MIN_LONG_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
Expand Down Expand Up @@ -107,9 +110,46 @@ public static long toLongExact(Number n) {
}
}

/** Return the {@link BigInteger} that {@code n} stores, or throws an exception if the
* stored value cannot be converted to a {@link BigInteger} that stores the exact same
* value. */
public static BigInteger toBigIntegerExact(Number n) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof Long) {
return BigInteger.valueOf(n.longValue());
} else if (n instanceof Float || n instanceof Double) {
double d = n.doubleValue();
if (d != Math.round(d)) {
throw new IllegalArgumentException(n + " is not an integer value");
}
return BigInteger.valueOf(n.longValue());
} else if (n instanceof BigDecimal) {
return ((BigDecimal) n).toBigIntegerExact();
} else if (n instanceof BigInteger) {
return ((BigInteger) n);
} else {
throw new IllegalArgumentException(
"Cannot check whether [" + n + "] of class [" + n.getClass().getName() + "] is actually a long"
);
}
}

/** Return the unsigned long (as {@link BigInteger}) that {@code n} stores, or throws an exception if the
* stored value cannot be converted to an unsigned long that stores the exact same
* value. */
public static BigInteger toUnsignedLongExact(Number value) {
final BigInteger v = Numbers.toBigIntegerExact(value);

if (v.compareTo(Numbers.MAX_UNSIGNED_LONG_VALUE) > 0 || v.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("Value [" + value + "] is out of range for an unsigned long");
}

return v;
}

// weak bounds on the BigDecimal representation to allow for coercion
private static BigDecimal BIGDECIMAL_GREATER_THAN_LONG_MAX_VALUE = BigDecimal.valueOf(Long.MAX_VALUE).add(BigDecimal.ONE);
private static BigDecimal BIGDECIMAL_LESS_THAN_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE).subtract(BigDecimal.ONE);
private static BigDecimal BIGDECIMAL_GREATER_THAN_USIGNED_LONG_MAX_VALUE = new BigDecimal(MAX_UNSIGNED_LONG_VALUE).add(BigDecimal.ONE);

/** Return the long that {@code stringValue} stores or throws an exception if the
* stored value cannot be converted to a long that stores the exact same
Expand Down Expand Up @@ -142,6 +182,31 @@ public static long toLong(String stringValue, boolean coerce) {
return bigIntegerValue.longValue();
}

/** Return the long that {@code stringValue} stores or throws an exception if the
* stored value cannot be converted to a long that stores the exact same
* value and {@code coerce} is false. */
public static BigInteger toUnsignedLong(String stringValue, boolean coerce) {
final BigInteger bigIntegerValue;
try {
BigDecimal bigDecimalValue = new BigDecimal(stringValue);
if (bigDecimalValue.compareTo(BIGDECIMAL_GREATER_THAN_USIGNED_LONG_MAX_VALUE) >= 0
|| bigDecimalValue.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Value [" + stringValue + "] is out of range for a long");
}
bigIntegerValue = coerce ? bigDecimalValue.toBigInteger() : bigDecimalValue.toBigIntegerExact();
} catch (ArithmeticException e) {
throw new IllegalArgumentException("Value [" + stringValue + "] has a decimal part");
} catch (NumberFormatException e) {
throw new IllegalArgumentException("For input string: \"" + stringValue + "\"");
}

if (bigIntegerValue.compareTo(MAX_UNSIGNED_LONG_VALUE) > 0 || bigIntegerValue.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("Value [" + stringValue + "] is out of range for a long");
}

return bigIntegerValue;
}

/** Return the int that {@code n} stores, or throws an exception if the
* stored value cannot be converted to an int that stores the exact same
* value. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public enum NumericType {
SHORT(false, SortField.Type.LONG, CoreValuesSourceType.NUMERIC),
INT(false, SortField.Type.LONG, CoreValuesSourceType.NUMERIC),
LONG(false, SortField.Type.LONG, CoreValuesSourceType.NUMERIC),
UNSIGNED_LONG(false, SortField.Type.LONG, CoreValuesSourceType.NUMERIC),
DATE(false, SortField.Type.LONG, CoreValuesSourceType.DATE),
DATE_NANOSECONDS(false, SortField.Type.LONG, CoreValuesSourceType.DATE),
HALF_FLOAT(true, SortField.Type.LONG, CoreValuesSourceType.NUMERIC),
Expand Down
Loading

0 comments on commit a1fc76e

Please sign in to comment.