blob: f8a8b933eb4c5a1d1b3d79380566546b17ba2539 [file] [log] [blame]
package org.apache.vxquery.datamodel.accessors.atomic;
import edu.uci.ics.hyracks.api.dataflow.value.ITypeTraits;
import edu.uci.ics.hyracks.data.std.api.AbstractPointable;
import edu.uci.ics.hyracks.data.std.api.IComparable;
import edu.uci.ics.hyracks.data.std.api.IHashable;
import edu.uci.ics.hyracks.data.std.api.INumeric;
import edu.uci.ics.hyracks.data.std.api.IPointable;
import edu.uci.ics.hyracks.data.std.api.IPointableFactory;
import edu.uci.ics.hyracks.data.std.primitive.BytePointable;
import edu.uci.ics.hyracks.data.std.primitive.LongPointable;
public class XSDecimalPointable extends AbstractPointable implements IHashable, IComparable, INumeric {
private final static int DECIMAL_PLACE_OFFSET = 0;
private final static int VALUE_OFFSET = 1;
public final static int PRECISION = 18;
public static final ITypeTraits TYPE_TRAITS = new ITypeTraits() {
private static final long serialVersionUID = 1L;
@Override
public boolean isFixedLength() {
return true;
}
@Override
public int getFixedLength() {
return 9;
}
};
public static final IPointableFactory FACTORY = new IPointableFactory() {
private static final long serialVersionUID = 1L;
@Override
public IPointable createPointable() {
return new XSDecimalPointable();
}
@Override
public ITypeTraits getTypeTraits() {
return TYPE_TRAITS;
}
};
@Override
public int compareTo(byte[] bytes, int start, int length) {
long v = getDecimalValue();
byte p = getDecimalPlace();
long ov = getDecimalValue(bytes, start);
byte op = getDecimalPlace(bytes, start);
// Make both long values have the decimal point at the same place.
// TODO double check that precision is not being lost.
int diff = p - op;
if (diff > 0) {
v = Math.round(v / Math.pow(10, diff));
} else if (diff < 0) {
ov = Math.round(ov / Math.pow(10, diff));
}
return v < ov ? -1 : (v > ov ? 1 : 0);
}
@Override
public int compareTo(IPointable pointer) {
return compareTo(pointer.getByteArray(), pointer.getStartOffset(), pointer.getLength());
}
public void setDecimal(long value, byte decimalPlace) {
BytePointable.setByte(bytes, start + DECIMAL_PLACE_OFFSET, decimalPlace);
LongPointable.setLong(bytes, start + VALUE_OFFSET, value);
normalize();
}
public void normalize() {
normalize(bytes, start);
}
public static void normalize(byte[] bytes, int start) {
byte decimalPlace = getDecimalPlace(bytes, start);
long value = getDecimalValue(bytes, start);
// Normalize the value and take off trailing zeros.
while (value != 0 && value % 10 == 0) {
value -= 10;
--decimalPlace;
}
BytePointable.setByte(bytes, start + DECIMAL_PLACE_OFFSET, decimalPlace);
LongPointable.setLong(bytes, start + VALUE_OFFSET, value);
}
public byte getDecimalPlace() {
return BytePointable.getByte(bytes, start + DECIMAL_PLACE_OFFSET);
}
public static byte getDecimalPlace(byte[] bytes, int start) {
return BytePointable.getByte(bytes, start + DECIMAL_PLACE_OFFSET);
}
public long getDecimalValue() {
return LongPointable.getLong(bytes, start + VALUE_OFFSET);
}
public static long getDecimalValue(byte[] bytes, int start) {
return LongPointable.getLong(bytes, start + VALUE_OFFSET);
}
@Override
public int hash() {
long v = getDecimalValue();
return (int) (v ^ (v >>> 32));
}
public long getBeforeDecimalPlace() {
return getBeforeDecimalPlace(bytes, start);
}
public static long getBeforeDecimalPlace(byte[] bytes, int start) {
return Math.round(getDecimalValue(bytes, start) / Math.pow(10, getDecimalPlace(bytes, start)));
}
public byte getDigitCount() {
return getDigitCount(bytes, start);
}
public static byte getDigitCount(byte[] bytes, int start) {
return (byte) (Math.log10((double) getDecimalValue(bytes, start)) + 1);
}
@Override
public byte byteValue() {
return (byte) getBeforeDecimalPlace();
}
@Override
public short shortValue() {
return (short) getBeforeDecimalPlace();
}
@Override
public int intValue() {
return (int) getBeforeDecimalPlace();
}
@Override
public long longValue() {
return getBeforeDecimalPlace();
}
@Override
public float floatValue() {
return (float) (getDecimalValue() / Math.pow(10, getDecimalPlace()));
}
@Override
public double doubleValue() {
return getDecimalValue() / Math.pow(10, getDecimalPlace());
}
}