• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.impl.number;
5 
6 import java.math.BigDecimal;
7 import java.math.BigInteger;
8 
9 /**
10  * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a byte array for numbers
11  * that don't fit into the standard BCD.
12  * @hide exposed on OHOS
13  */
14 public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_AbstractBCD {
15 
16     /**
17      * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map to
18      * one digit. For example, the number "12345" in BCD is "0x12345".
19      *
20      * <p>
21      * Whenever bcd changes internally, {@link #compact()} must be called, except in special cases like
22      * setting the digit to zero.
23      */
24     private byte[] bcdBytes;
25 
26     private long bcdLong = 0L;
27 
28     private boolean usingBytes = false;
29 
30     @Override
maxRepresentableDigits()31     public int maxRepresentableDigits() {
32         return Integer.MAX_VALUE;
33     }
34 
DecimalQuantity_DualStorageBCD()35     public DecimalQuantity_DualStorageBCD() {
36         setBcdToZero();
37         flags = 0;
38     }
39 
DecimalQuantity_DualStorageBCD(long input)40     public DecimalQuantity_DualStorageBCD(long input) {
41         setToLong(input);
42     }
43 
DecimalQuantity_DualStorageBCD(int input)44     public DecimalQuantity_DualStorageBCD(int input) {
45         setToInt(input);
46     }
47 
DecimalQuantity_DualStorageBCD(double input)48     public DecimalQuantity_DualStorageBCD(double input) {
49         setToDouble(input);
50     }
51 
DecimalQuantity_DualStorageBCD(BigInteger input)52     public DecimalQuantity_DualStorageBCD(BigInteger input) {
53         setToBigInteger(input);
54     }
55 
DecimalQuantity_DualStorageBCD(BigDecimal input)56     public DecimalQuantity_DualStorageBCD(BigDecimal input) {
57         setToBigDecimal(input);
58     }
59 
DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other)60     public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other) {
61         copyFrom(other);
62     }
63 
DecimalQuantity_DualStorageBCD(Number number)64     public DecimalQuantity_DualStorageBCD(Number number) {
65         // NOTE: Number type expansion happens both here
66         // and in NumberFormat.java
67         if (number instanceof Long) {
68             setToLong(number.longValue());
69         } else if (number instanceof Integer) {
70             setToInt(number.intValue());
71         } else if (number instanceof Float) {
72             setToDouble(number.doubleValue());
73         } else if (number instanceof Double) {
74             setToDouble(number.doubleValue());
75         } else if (number instanceof BigInteger) {
76             setToBigInteger((BigInteger) number);
77         } else if (number instanceof BigDecimal) {
78             setToBigDecimal((BigDecimal) number);
79         } else if (number instanceof ohos.global.icu.math.BigDecimal) {
80             setToBigDecimal(((ohos.global.icu.math.BigDecimal) number).toBigDecimal());
81         } else {
82             throw new IllegalArgumentException(
83                     "Number is of an unsupported type: " + number.getClass().getName());
84         }
85     }
86 
87     @Override
createCopy()88     public DecimalQuantity createCopy() {
89         return new DecimalQuantity_DualStorageBCD(this);
90     }
91 
92     @Override
getDigitPos(int position)93     protected byte getDigitPos(int position) {
94         if (usingBytes) {
95             if (position < 0 || position >= precision)
96                 return 0;
97             return bcdBytes[position];
98         } else {
99             if (position < 0 || position >= 16)
100                 return 0;
101             return (byte) ((bcdLong >>> (position * 4)) & 0xf);
102         }
103     }
104 
105     @Override
setDigitPos(int position, byte value)106     protected void setDigitPos(int position, byte value) {
107         assert position >= 0;
108         if (usingBytes) {
109             ensureCapacity(position + 1);
110             bcdBytes[position] = value;
111         } else if (position >= 16) {
112             switchStorage();
113             ensureCapacity(position + 1);
114             bcdBytes[position] = value;
115         } else {
116             int shift = position * 4;
117             bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift);
118         }
119     }
120 
121     @Override
shiftLeft(int numDigits)122     protected void shiftLeft(int numDigits) {
123         if (!usingBytes && precision + numDigits > 16) {
124             switchStorage();
125         }
126         if (usingBytes) {
127             ensureCapacity(precision + numDigits);
128             int i = precision + numDigits - 1;
129             for (; i >= numDigits; i--) {
130                 bcdBytes[i] = bcdBytes[i - numDigits];
131             }
132             for (; i >= 0; i--) {
133                 bcdBytes[i] = 0;
134             }
135         } else {
136             bcdLong <<= (numDigits * 4);
137         }
138         scale -= numDigits;
139         precision += numDigits;
140     }
141 
142     @Override
shiftRight(int numDigits)143     protected void shiftRight(int numDigits) {
144         if (usingBytes) {
145             int i = 0;
146             for (; i < precision - numDigits; i++) {
147                 bcdBytes[i] = bcdBytes[i + numDigits];
148             }
149             for (; i < precision; i++) {
150                 bcdBytes[i] = 0;
151             }
152         } else {
153             bcdLong >>>= (numDigits * 4);
154         }
155         scale += numDigits;
156         precision -= numDigits;
157     }
158 
159     @Override
popFromLeft(int numDigits)160     protected void popFromLeft(int numDigits) {
161         assert numDigits <= precision;
162         if (usingBytes) {
163             int i = precision - 1;
164             for (; i >= precision - numDigits; i--) {
165                 bcdBytes[i] = 0;
166             }
167         } else {
168             bcdLong &= (1L << ((precision - numDigits) * 4)) - 1;
169         }
170         precision -= numDigits;
171     }
172 
173     @Override
setBcdToZero()174     protected void setBcdToZero() {
175         if (usingBytes) {
176             bcdBytes = null;
177             usingBytes = false;
178         }
179         bcdLong = 0L;
180         scale = 0;
181         precision = 0;
182         isApproximate = false;
183         origDouble = 0;
184         origDelta = 0;
185         exponent = 0;
186     }
187 
188     @Override
readIntToBcd(int n)189     protected void readIntToBcd(int n) {
190         assert n != 0;
191         // ints always fit inside the long implementation.
192         long result = 0L;
193         int i = 16;
194         for (; n != 0; n /= 10, i--) {
195             result = (result >>> 4) + (((long) n % 10) << 60);
196         }
197         assert !usingBytes;
198         bcdLong = result >>> (i * 4);
199         scale = 0;
200         precision = 16 - i;
201     }
202 
203     @Override
readLongToBcd(long n)204     protected void readLongToBcd(long n) {
205         assert n != 0;
206         if (n >= 10000000000000000L) {
207             ensureCapacity();
208             int i = 0;
209             for (; n != 0L; n /= 10L, i++) {
210                 bcdBytes[i] = (byte) (n % 10);
211             }
212             assert usingBytes;
213             scale = 0;
214             precision = i;
215         } else {
216             long result = 0L;
217             int i = 16;
218             for (; n != 0L; n /= 10L, i--) {
219                 result = (result >>> 4) + ((n % 10) << 60);
220             }
221             assert i >= 0;
222             assert !usingBytes;
223             bcdLong = result >>> (i * 4);
224             scale = 0;
225             precision = 16 - i;
226         }
227     }
228 
229     @Override
readBigIntegerToBcd(BigInteger n)230     protected void readBigIntegerToBcd(BigInteger n) {
231         assert n.signum() != 0;
232         ensureCapacity(); // allocate initial byte array
233         int i = 0;
234         for (; n.signum() != 0; i++) {
235             BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN);
236             ensureCapacity(i + 1);
237             bcdBytes[i] = temp[1].byteValue();
238             n = temp[0];
239         }
240         scale = 0;
241         precision = i;
242     }
243 
244     @Override
bcdToBigDecimal()245     protected BigDecimal bcdToBigDecimal() {
246         if (usingBytes) {
247             // Converting to a string here is faster than doing BigInteger/BigDecimal arithmetic.
248             BigDecimal result = new BigDecimal(toNumberString());
249             if (isNegative()) {
250                 result = result.negate();
251             }
252             return result;
253         } else {
254             long tempLong = 0L;
255             for (int shift = (precision - 1); shift >= 0; shift--) {
256                 tempLong = tempLong * 10 + getDigitPos(shift);
257             }
258             BigDecimal result = BigDecimal.valueOf(tempLong);
259             // Test that the new scale fits inside the BigDecimal
260             long newScale = result.scale() + scale + exponent;
261             if (newScale <= Integer.MIN_VALUE) {
262                 result = BigDecimal.ZERO;
263             } else {
264                 result = result.scaleByPowerOfTen(scale + exponent);
265             }
266             if (isNegative()) {
267                 result = result.negate();
268             }
269             return result;
270         }
271     }
272 
273     @Override
compact()274     protected void compact() {
275         if (usingBytes) {
276             int delta = 0;
277             for (; delta < precision && bcdBytes[delta] == 0; delta++)
278                 ;
279             if (delta == precision) {
280                 // Number is zero
281                 setBcdToZero();
282                 return;
283             } else {
284                 // Remove trailing zeros
285                 shiftRight(delta);
286             }
287 
288             // Compute precision
289             int leading = precision - 1;
290             for (; leading >= 0 && bcdBytes[leading] == 0; leading--)
291                 ;
292             precision = leading + 1;
293 
294             // Switch storage mechanism if possible
295             if (precision <= 16) {
296                 switchStorage();
297             }
298 
299         } else {
300             if (bcdLong == 0L) {
301                 // Number is zero
302                 setBcdToZero();
303                 return;
304             }
305 
306             // Compact the number (remove trailing zeros)
307             int delta = Long.numberOfTrailingZeros(bcdLong) / 4;
308             bcdLong >>>= delta * 4;
309             scale += delta;
310 
311             // Compute precision
312             precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4);
313         }
314     }
315 
316     /** Ensure that a byte array of at least 40 digits is allocated. */
ensureCapacity()317     private void ensureCapacity() {
318         ensureCapacity(40);
319     }
320 
ensureCapacity(int capacity)321     private void ensureCapacity(int capacity) {
322         if (capacity == 0)
323             return;
324         int oldCapacity = usingBytes ? bcdBytes.length : 0;
325         if (!usingBytes) {
326             bcdBytes = new byte[capacity];
327         } else if (oldCapacity < capacity) {
328             byte[] bcd1 = new byte[capacity * 2];
329             System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity);
330             bcdBytes = bcd1;
331         }
332         usingBytes = true;
333     }
334 
335     /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
switchStorage()336     private void switchStorage() {
337         if (usingBytes) {
338             // Change from bytes to long
339             bcdLong = 0L;
340             for (int i = precision - 1; i >= 0; i--) {
341                 bcdLong <<= 4;
342                 bcdLong |= bcdBytes[i];
343             }
344             bcdBytes = null;
345             usingBytes = false;
346         } else {
347             // Change from long to bytes
348             ensureCapacity();
349             for (int i = 0; i < precision; i++) {
350                 bcdBytes[i] = (byte) (bcdLong & 0xf);
351                 bcdLong >>>= 4;
352             }
353             assert usingBytes;
354         }
355     }
356 
357     @Override
copyBcdFrom(DecimalQuantity _other)358     protected void copyBcdFrom(DecimalQuantity _other) {
359         DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD) _other;
360         setBcdToZero();
361         if (other.usingBytes) {
362             ensureCapacity(other.precision);
363             System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision);
364         } else {
365             bcdLong = other.bcdLong;
366         }
367     }
368 
369     /**
370      * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
371      *
372      * @return An error message if this instance is invalid, or null if this instance is healthy.
373      * @deprecated This API is for ICU internal use only.
374      * @hide draft / provisional / internal are hidden on OHOS
375      */
376     @Deprecated
checkHealth()377     public String checkHealth() {
378         if (usingBytes) {
379             if (bcdLong != 0)
380                 return "Value in bcdLong but we are in byte mode";
381             if (precision == 0)
382                 return "Zero precision but we are in byte mode";
383             if (precision > bcdBytes.length)
384                 return "Precision exceeds length of byte array";
385             if (getDigitPos(precision - 1) == 0)
386                 return "Most significant digit is zero in byte mode";
387             if (getDigitPos(0) == 0)
388                 return "Least significant digit is zero in long mode";
389             for (int i = 0; i < precision; i++) {
390                 if (getDigitPos(i) >= 10)
391                     return "Digit exceeding 10 in byte array";
392                 if (getDigitPos(i) < 0)
393                     return "Digit below 0 in byte array";
394             }
395             for (int i = precision; i < bcdBytes.length; i++) {
396                 if (getDigitPos(i) != 0)
397                     return "Nonzero digits outside of range in byte array";
398             }
399         } else {
400             if (bcdBytes != null) {
401                 for (int i = 0; i < bcdBytes.length; i++) {
402                     if (bcdBytes[i] != 0)
403                         return "Nonzero digits in byte array but we are in long mode";
404                 }
405             }
406             if (precision == 0 && bcdLong != 0)
407                 return "Value in bcdLong even though precision is zero";
408             if (precision > 16)
409                 return "Precision exceeds length of long";
410             if (precision != 0 && getDigitPos(precision - 1) == 0)
411                 return "Most significant digit is zero in long mode";
412             if (precision != 0 && getDigitPos(0) == 0)
413                 return "Least significant digit is zero in long mode";
414             for (int i = 0; i < precision; i++) {
415                 if (getDigitPos(i) >= 10)
416                     return "Digit exceeding 10 in long";
417                 if (getDigitPos(i) < 0)
418                     return "Digit below 0 in long (?!)";
419             }
420             for (int i = precision; i < 16; i++) {
421                 if (getDigitPos(i) != 0)
422                     return "Nonzero digits outside of range in long";
423             }
424         }
425 
426         return null;
427     }
428 
429     /**
430      * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its internal byte array
431      * storage mechanism.
432      *
433      * @return true if an internal byte array is being used; false if a long is being used.
434      * @deprecated This API is ICU internal only.
435      * @hide draft / provisional / internal are hidden on OHOS
436      */
437     @Deprecated
isUsingBytes()438     public boolean isUsingBytes() {
439         return usingBytes;
440     }
441 
442     @Override
toString()443     public String toString() {
444         return String.format("<DecimalQuantity %d:%d %s %s%s>",
445                 lReqPos,
446                 rReqPos,
447                 (usingBytes ? "bytes" : "long"),
448                 (isNegative() ? "-" : ""),
449                 toNumberString());
450     }
451 
toNumberString()452     private String toNumberString() {
453         StringBuilder sb = new StringBuilder();
454         if (usingBytes) {
455             if (precision == 0) {
456                 sb.append('0');
457             }
458             for (int i = precision - 1; i >= 0; i--) {
459                 sb.append(bcdBytes[i]);
460             }
461         } else {
462             sb.append(Long.toHexString(bcdLong));
463         }
464         sb.append("E");
465         sb.append(scale);
466         return sb.toString();
467     }
468 }
469