| /* |
| * 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 License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.vxquery.datamodel.accessors.atomic; |
| |
| import org.apache.hyracks.api.dataflow.value.ITypeTraits; |
| import org.apache.hyracks.data.std.api.AbstractPointable; |
| import org.apache.hyracks.data.std.api.IComparable; |
| import org.apache.hyracks.data.std.api.IHashable; |
| import org.apache.hyracks.data.std.api.INumeric; |
| import org.apache.hyracks.data.std.api.IPointable; |
| import org.apache.hyracks.data.std.api.IPointableFactory; |
| import org.apache.hyracks.data.std.primitive.BytePointable; |
| import org.apache.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) { |
| ov = (long) (ov * Math.pow(10, diff)); |
| } else if (diff < 0) { |
| v = (long) (v * Math.pow(10, Math.abs(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); |
| } |
| |
| public static byte getDecimalPlace(byte[] bytes, int start) { |
| return BytePointable.getByte(bytes, start + DECIMAL_PLACE_OFFSET); |
| } |
| |
| public long getDecimalValue() { |
| return getDecimalValue(bytes, start); |
| } |
| |
| 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 getBeforeDecimalPlaceRounded() { |
| return getBeforeDecimalPlaceRounded(bytes, start); |
| } |
| |
| public static long getBeforeDecimalPlaceRounded(byte[] bytes, int start) { |
| if (getDecimalPlace(bytes, start) != 0) { |
| return Math.round(getDecimalValue(bytes, start) / Math.pow(10, getDecimalPlace(bytes, start))); |
| } else { |
| return getDecimalValue(bytes, start); |
| } |
| } |
| |
| public long getBeforeDecimalPlace() { |
| return getBeforeDecimalPlace(bytes, start); |
| } |
| |
| public static long getBeforeDecimalPlace(byte[] bytes, int start) { |
| if (getDecimalPlace(bytes, start) != 0) { |
| return (long) (getDecimalValue(bytes, start) / Math.pow(10, getDecimalPlace(bytes, start))); |
| } else { |
| return getDecimalValue(bytes, start); |
| } |
| |
| } |
| |
| public byte getDigitCount() { |
| return getDigitCount(bytes, start); |
| } |
| |
| public static byte getDigitCount(byte[] bytes, int start) { |
| long value = getDecimalValue(bytes, start); |
| if (value < 0) { |
| value *= -1; |
| } |
| long check = 10; |
| for (byte i = 1; i < PRECISION; i++) { |
| if (value < check) |
| return i; |
| check *= 10; |
| } |
| return PRECISION; |
| } |
| |
| @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 ((double) getDecimalValue()) / Math.pow(10, getDecimalPlace()); |
| } |
| |
| } |