f60d9bdc4917d0ac9660b20de0e3b14248b89daa
[vxquery.git] / vxquery-core / src / main / java / org / apache / vxquery / datamodel / accessors / atomic / XSDecimalPointable.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.vxquery.datamodel.accessors.atomic;
18
19 import edu.uci.ics.hyracks.api.dataflow.value.ITypeTraits;
20 import edu.uci.ics.hyracks.data.std.api.AbstractPointable;
21 import edu.uci.ics.hyracks.data.std.api.IComparable;
22 import edu.uci.ics.hyracks.data.std.api.IHashable;
23 import edu.uci.ics.hyracks.data.std.api.INumeric;
24 import edu.uci.ics.hyracks.data.std.api.IPointable;
25 import edu.uci.ics.hyracks.data.std.api.IPointableFactory;
26 import edu.uci.ics.hyracks.data.std.primitive.BytePointable;
27 import edu.uci.ics.hyracks.data.std.primitive.LongPointable;
28
29 public class XSDecimalPointable extends AbstractPointable implements IHashable, IComparable, INumeric {
30     private final static int DECIMAL_PLACE_OFFSET = 0;
31     private final static int VALUE_OFFSET = 1;
32     public final static int PRECISION = 18;
33
34     public static final ITypeTraits TYPE_TRAITS = new ITypeTraits() {
35         private static final long serialVersionUID = 1L;
36
37         @Override
38         public boolean isFixedLength() {
39             return true;
40         }
41
42         @Override
43         public int getFixedLength() {
44             return 9;
45         }
46     };
47
48     public static final IPointableFactory FACTORY = new IPointableFactory() {
49         private static final long serialVersionUID = 1L;
50
51         @Override
52         public IPointable createPointable() {
53             return new XSDecimalPointable();
54         }
55
56         @Override
57         public ITypeTraits getTypeTraits() {
58             return TYPE_TRAITS;
59         }
60     };
61
62     @Override
63     public int compareTo(byte[] bytes, int start, int length) {
64         long v = getDecimalValue();
65         byte p = getDecimalPlace();
66         long ov = getDecimalValue(bytes, start);
67         byte op = getDecimalPlace(bytes, start);
68
69         // Make both long values have the decimal point at the same place. 
70         // TODO double check that precision is not being lost.
71         int diff = p - op;
72         if (diff > 0) {
73             ov = (long) (ov * Math.pow(10, diff));
74         } else if (diff < 0) {
75             v = (long) (v * Math.pow(10, Math.abs(diff)));
76         }
77
78         return v < ov ? -1 : (v > ov ? 1 : 0);
79     }
80
81     @Override
82     public int compareTo(IPointable pointer) {
83         return compareTo(pointer.getByteArray(), pointer.getStartOffset(), pointer.getLength());
84     }
85
86     public void setDecimal(long value, byte decimalPlace) {
87         BytePointable.setByte(bytes, start + DECIMAL_PLACE_OFFSET, decimalPlace);
88         LongPointable.setLong(bytes, start + VALUE_OFFSET, value);
89         normalize();
90     }
91
92     public void normalize() {
93         normalize(bytes, start);
94     }
95
96     public static void normalize(byte[] bytes, int start) {
97         byte decimalPlace = getDecimalPlace(bytes, start);
98         long value = getDecimalValue(bytes, start);
99         // Normalize the value and take off trailing zeros.
100         while (value != 0 && value % 10 == 0) {
101             value /= 10;
102             --decimalPlace;
103         }
104         BytePointable.setByte(bytes, start + DECIMAL_PLACE_OFFSET, decimalPlace);
105         LongPointable.setLong(bytes, start + VALUE_OFFSET, value);
106     }
107
108     public byte getDecimalPlace() {
109         return BytePointable.getByte(bytes, start);
110     }
111
112     public static byte getDecimalPlace(byte[] bytes, int start) {
113         return BytePointable.getByte(bytes, start + DECIMAL_PLACE_OFFSET);
114     }
115
116     public long getDecimalValue() {
117         return getDecimalValue(bytes, start);
118     }
119
120     public static long getDecimalValue(byte[] bytes, int start) {
121         return LongPointable.getLong(bytes, start + VALUE_OFFSET);
122     }
123
124     @Override
125     public int hash() {
126         long v = getDecimalValue();
127         return (int) (v ^ (v >>> 32));
128     }
129
130     public long getBeforeDecimalPlaceRounded() {
131         return getBeforeDecimalPlaceRounded(bytes, start);
132     }
133
134     public static long getBeforeDecimalPlaceRounded(byte[] bytes, int start) {
135         if (getDecimalPlace(bytes, start) != 0) {
136             return Math.round(getDecimalValue(bytes, start) / Math.pow(10, getDecimalPlace(bytes, start)));
137         } else {
138             return getDecimalValue(bytes, start);
139         }
140     }
141
142     public long getBeforeDecimalPlace() {
143         return getBeforeDecimalPlace(bytes, start);
144     }
145
146     public static long getBeforeDecimalPlace(byte[] bytes, int start) {
147         if (getDecimalPlace(bytes, start) != 0) {
148             return (long) (getDecimalValue(bytes, start) / Math.pow(10, getDecimalPlace(bytes, start)));
149         } else {
150             return getDecimalValue(bytes, start);
151         }
152
153     }
154
155     public byte getDigitCount() {
156         return getDigitCount(bytes, start);
157     }
158
159     public static byte getDigitCount(byte[] bytes, int start) {
160         long value = getDecimalValue(bytes, start);
161         if (value < 0) {
162             value *= -1;
163         }
164         long check = 10;
165         for (byte i = 1; i < PRECISION; i++) {
166             if (value < check)
167                 return i;
168             check *= 10;
169         }
170         return PRECISION;
171     }
172
173     @Override
174     public byte byteValue() {
175         return (byte) getBeforeDecimalPlace();
176     }
177
178     @Override
179     public short shortValue() {
180         return (short) getBeforeDecimalPlace();
181     }
182
183     @Override
184     public int intValue() {
185         return (int) getBeforeDecimalPlace();
186     }
187
188     @Override
189     public long longValue() {
190         return getBeforeDecimalPlace();
191     }
192
193     @Override
194     public float floatValue() {
195         return (float) (getDecimalValue() / Math.pow(10, getDecimalPlace()));
196     }
197
198     @Override
199     public double doubleValue() {
200         return ((double) getDecimalValue()) / Math.pow(10, getDecimalPlace());
201     }
202
203 }