2017-06-27 10:22:10 +08:00
|
|
|
/*
|
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with this
|
|
|
|
|
* work for additional information regarding copyright ownership. The ASF
|
|
|
|
|
* licenses this file to You under the Apache License, Version 2.0 (the
|
|
|
|
|
* "License"); you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
2017-08-16 18:31:55 +08:00
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
2017-06-27 10:22:10 +08:00
|
|
|
*/
|
2017-08-17 16:07:46 +08:00
|
|
|
|
2017-06-27 10:22:10 +08:00
|
|
|
package com.baidu.hugegraph.util;
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This file is copied verbatim from Apache Lucene NumericUtils.java Only the
|
|
|
|
|
* double/float to sortable long/int conversions are retained.
|
|
|
|
|
*/
|
|
|
|
|
public final class NumericUtil {
|
|
|
|
|
|
|
|
|
|
private NumericUtil() {
|
2017-12-07 21:59:29 +08:00
|
|
|
}
|
2017-06-27 10:22:10 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a <code>double</code> value to a sortable signed
|
|
|
|
|
* <code>long</code>. The value is converted by getting their IEEE 754
|
|
|
|
|
* floating-point "double format" bit layout and then some bits
|
|
|
|
|
* are swapped, to be able to compare the result as long. By this the
|
|
|
|
|
* precision is not reduced, but the value can easily used as a long. The
|
|
|
|
|
* sort order (including {@link Double#NaN}) is defined by
|
|
|
|
|
* {@link Double#compareTo}; {@code NaN} is greater than positive infinity.
|
|
|
|
|
*
|
|
|
|
|
* @see #sortableLongToDouble
|
|
|
|
|
*/
|
|
|
|
|
public static long doubleToSortableLong(double val) {
|
|
|
|
|
return sortableDoubleBits(Double.doubleToLongBits(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a sortable <code>long</code> back to a <code>double</code>.
|
|
|
|
|
*
|
|
|
|
|
* @see #doubleToSortableLong
|
|
|
|
|
*/
|
|
|
|
|
public static double sortableLongToDouble(long val) {
|
|
|
|
|
return Double.longBitsToDouble(sortableDoubleBits(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a <code>float</code> value to a sortable signed
|
|
|
|
|
* <code>int</code>. The value is converted by getting their IEEE 754
|
|
|
|
|
* floating-point "float format" bit layout and then some bits are
|
|
|
|
|
* swapped, to be able to compare the result as int. By this the precision
|
|
|
|
|
* is not reduced, but the value can easily used as an int. The sort order
|
|
|
|
|
* (including {@link Float#NaN}) is defined by {@link Float#compareTo};
|
|
|
|
|
* {@code NaN} is greater than positive infinity.
|
|
|
|
|
*
|
|
|
|
|
* @see #sortableIntToFloat
|
|
|
|
|
*/
|
|
|
|
|
public static int floatToSortableInt(float val) {
|
|
|
|
|
return sortableFloatBits(Float.floatToIntBits(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a sortable <code>int</code> back to a <code>float</code>.
|
|
|
|
|
*
|
|
|
|
|
* @see #floatToSortableInt
|
|
|
|
|
*/
|
|
|
|
|
public static float sortableIntToFloat(int val) {
|
|
|
|
|
return Float.intBitsToFloat(sortableFloatBits(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts IEEE 754 representation of a double to sortable order (or back
|
|
|
|
|
* to the original)
|
|
|
|
|
*/
|
|
|
|
|
public static long sortableDoubleBits(long bits) {
|
|
|
|
|
return bits ^ (bits >> 63) & 0x7fffffffffffffffL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts IEEE 754 representation of a float to sortable order (or back to
|
|
|
|
|
* the original)
|
|
|
|
|
*/
|
|
|
|
|
public static int sortableFloatBits(int bits) {
|
|
|
|
|
return bits ^ (bits >> 31) & 0x7fffffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
2017-12-07 21:59:29 +08:00
|
|
|
public static byte[] numberToSortableBytes(Number number) {
|
|
|
|
|
if (number instanceof Long) {
|
|
|
|
|
return longToBytes(number.longValue());
|
|
|
|
|
} else if (number instanceof Double) {
|
|
|
|
|
return longToBytes(doubleToSortableLong(number.doubleValue()));
|
|
|
|
|
} else if (number instanceof Float) {
|
|
|
|
|
return intToBytes(floatToSortableInt(number.floatValue()));
|
|
|
|
|
} else if (number instanceof Integer || number instanceof Short) {
|
|
|
|
|
return intToBytes(number.intValue());
|
|
|
|
|
} else if (number instanceof Byte) {
|
|
|
|
|
return new byte[]{number.byteValue()} ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: support other number types
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Number sortableBytesToNumber(byte[] bytes, Class<?> clazz) {
|
|
|
|
|
assert NumericUtil.isNumber(clazz);
|
|
|
|
|
|
|
|
|
|
if (clazz == Long.class) {
|
|
|
|
|
return bytesToLong(bytes);
|
|
|
|
|
} else if (clazz == Double.class) {
|
|
|
|
|
return sortableLongToDouble(bytesToLong(bytes));
|
|
|
|
|
} else if (clazz == Float.class) {
|
|
|
|
|
return sortableIntToFloat(bytesToInt(bytes));
|
|
|
|
|
} else if (clazz == Integer.class) {
|
|
|
|
|
return bytesToInt(bytes);
|
|
|
|
|
} else if (clazz == Short.class) {
|
|
|
|
|
return (short) bytesToInt(bytes);
|
|
|
|
|
} else if (clazz == Byte.class) {
|
|
|
|
|
return bytes[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: support other number types
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
2017-06-27 10:22:10 +08:00
|
|
|
public static byte[] longToBytes(long value) {
|
|
|
|
|
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
|
|
|
|
|
buffer.putLong(value);
|
|
|
|
|
return buffer.array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static long bytesToLong(byte[] bytes) {
|
2017-12-07 21:59:29 +08:00
|
|
|
assert bytes.length == Long.BYTES;
|
|
|
|
|
return ByteBuffer.wrap(bytes).getLong();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] intToBytes(int value) {
|
|
|
|
|
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
|
|
|
|
|
buffer.putInt(value);
|
|
|
|
|
return buffer.array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int bytesToInt(byte[] bytes) {
|
|
|
|
|
assert bytes.length == Integer.BYTES;
|
|
|
|
|
return ByteBuffer.wrap(bytes).getInt();
|
2017-06-27 10:22:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
|
|
|
|
public static boolean isNumber(Object value) {
|
|
|
|
|
if (value == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return isNumber(value.getClass());
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-07 21:59:29 +08:00
|
|
|
public static boolean isNumber(Class<?> clazz) {
|
|
|
|
|
return Number.class.isAssignableFrom(clazz);
|
2017-06-27 10:22:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
2017-12-07 21:59:29 +08:00
|
|
|
public static Object convertToNumber(Object value) {
|
2017-06-27 10:22:10 +08:00
|
|
|
if (!isNumber(value) && value != null) {
|
|
|
|
|
if (value instanceof Date) {
|
|
|
|
|
value = ((Date) value).getTime();
|
2017-12-07 21:59:29 +08:00
|
|
|
} else {
|
|
|
|
|
// TODO: add some more types to convert
|
|
|
|
|
value = new BigDecimal(value.toString());
|
2017-06-27 10:22:10 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
}
|