1495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert/* GENERATED SOURCE. DO NOT MODIFY. */
2495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert// © 2017 and later: Unicode, Inc. and others.
3495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
4495cb271e305cfb399d463f32210a371198f0abfFredrik Roubertpackage android.icu.impl.number;
5495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
6495cb271e305cfb399d463f32210a371198f0abfFredrik Roubertimport java.math.BigDecimal;
7495cb271e305cfb399d463f32210a371198f0abfFredrik Roubertimport java.math.BigInteger;
8495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
9495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert/**
1005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a byte array
1105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert * for numbers that don't fit into the standard BCD.
12495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert * @hide Only a subset of ICU is exposed in Android
13495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert */
1405fa7802d0874812c234a29745586677ee5837eaFredrik Roubertpublic final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_AbstractBCD {
15495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
16495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  /**
17495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map
18495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * to one digit. For example, the number "12345" in BCD is "0x12345".
19495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   *
20495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases
21495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * like setting the digit to zero.
22495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   */
23495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private byte[] bcdBytes;
24495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
25495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private long bcdLong = 0L;
26495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
27495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private boolean usingBytes = false;
28495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
29495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
30495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  public int maxRepresentableDigits() {
31495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    return Integer.MAX_VALUE;
32495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
33495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
3405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD() {
35495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setBcdToZero();
3605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    flags = 0;
37495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
38495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
3905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(long input) {
40495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setToLong(input);
41495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
42495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
4305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(int input) {
44495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setToInt(input);
45495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
46495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
4705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(double input) {
48495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setToDouble(input);
49495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
50495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
5105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(BigInteger input) {
52495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setToBigInteger(input);
53495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
54495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
5505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(BigDecimal input) {
56495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    setToBigDecimal(input);
57495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
58495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
5905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other) {
60495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    copyFrom(other);
61495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
62495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
6305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity_DualStorageBCD(Number number) {
64495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (number instanceof Long) {
65495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToLong(number.longValue());
66495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (number instanceof Integer) {
67495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToInt(number.intValue());
68495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (number instanceof Double) {
69495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToDouble(number.doubleValue());
70495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (number instanceof BigInteger) {
71495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToBigInteger((BigInteger) number);
72495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (number instanceof BigDecimal) {
73495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToBigDecimal((BigDecimal) number);
74495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (number instanceof android.icu.math.BigDecimal) {
75495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      setToBigDecimal(((android.icu.math.BigDecimal) number).toBigDecimal());
76495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
77495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      throw new IllegalArgumentException(
78495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert          "Number is of an unsupported type: " + number.getClass().getName());
79495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
80495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
81495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
82495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
8305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public DecimalQuantity createCopy() {
8405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    return new DecimalQuantity_DualStorageBCD(this);
8505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  }
8605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
8705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  @Override
88495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected byte getDigitPos(int position) {
89495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
90495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (position < 0 || position > precision) return 0;
91495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      return bcdBytes[position];
92495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
93495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (position < 0 || position >= 16) return 0;
94495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      return (byte) ((bcdLong >>> (position * 4)) & 0xf);
95495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
96495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
97495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
98495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
99495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void setDigitPos(int position, byte value) {
100495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    assert position >= 0;
101495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
102495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity(position + 1);
103495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdBytes[position] = value;
104495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else if (position >= 16) {
105495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      switchStorage();
106495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity(position + 1);
107495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdBytes[position] = value;
108495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
109495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int shift = position * 4;
110495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift);
111495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
112495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
113495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
114495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
115495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void shiftLeft(int numDigits) {
116495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (!usingBytes && precision + numDigits > 16) {
117495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      switchStorage();
118495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
119495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
120495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity(precision + numDigits);
121495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int i = precision + numDigits - 1;
122495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; i >= numDigits; i--) {
123495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = bcdBytes[i - numDigits];
124495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
125495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; i >= 0; i--) {
126495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = 0;
127495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
128495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
129495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong <<= (numDigits * 4);
130495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
131495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    scale -= numDigits;
132495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    precision += numDigits;
133495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
134495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
135495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
136495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void shiftRight(int numDigits) {
137495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
138495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int i = 0;
139495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; i < precision - numDigits; i++) {
140495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = bcdBytes[i + numDigits];
141495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
142495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; i < precision; i++) {
143495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = 0;
144495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
145495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
146495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong >>>= (numDigits * 4);
147495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
148495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    scale += numDigits;
149495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    precision -= numDigits;
150495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
151495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
152495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
153495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void setBcdToZero() {
154495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
15505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        bcdBytes = null;
15605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        usingBytes = false;
157495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
158495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    bcdLong = 0L;
159495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    scale = 0;
160495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    precision = 0;
161495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    isApproximate = false;
162495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    origDouble = 0;
163495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    origDelta = 0;
164495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
165495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
166495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
167495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void readIntToBcd(int n) {
168495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    assert n != 0;
169495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    // ints always fit inside the long implementation.
170495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    long result = 0L;
171495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    int i = 16;
172495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    for (; n != 0; n /= 10, i--) {
173495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      result = (result >>> 4) + (((long) n % 10) << 60);
174495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
17505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    assert !usingBytes;
176495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    bcdLong = result >>> (i * 4);
177495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    scale = 0;
178495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    precision = 16 - i;
179495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
180495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
181495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
182495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void readLongToBcd(long n) {
183495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    assert n != 0;
184495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (n >= 10000000000000000L) {
185495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity();
186495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int i = 0;
187495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; n != 0L; n /= 10L, i++) {
188495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = (byte) (n % 10);
189495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
19005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      assert usingBytes;
191495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      scale = 0;
192495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      precision = i;
193495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
194495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      long result = 0L;
195495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int i = 16;
196495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; n != 0L; n /= 10L, i--) {
197495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        result = (result >>> 4) + ((n % 10) << 60);
198495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
199495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      assert i >= 0;
20005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      assert !usingBytes;
201495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong = result >>> (i * 4);
202495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      scale = 0;
203495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      precision = 16 - i;
204495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
205495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
206495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
207495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
208495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void readBigIntegerToBcd(BigInteger n) {
209495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    assert n.signum() != 0;
210495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    ensureCapacity(); // allocate initial byte array
211495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    int i = 0;
212495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    for (; n.signum() != 0; i++) {
213495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN);
214495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity(i + 1);
215495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdBytes[i] = temp[1].byteValue();
216495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      n = temp[0];
217495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
218495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    scale = 0;
219495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    precision = i;
220495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
221495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
222495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
223495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected BigDecimal bcdToBigDecimal() {
224495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
225495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Converting to a string here is faster than doing BigInteger/BigDecimal arithmetic.
22605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      BigDecimal result = new BigDecimal(toNumberString());
22705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      if (isNegative()) {
22805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert          result = result.negate();
229495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
23005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      return result;
231495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
232495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      long tempLong = 0L;
233495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int shift = (precision - 1); shift >= 0; shift--) {
234495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        tempLong = tempLong * 10 + getDigitPos(shift);
235495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
236495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      BigDecimal result = BigDecimal.valueOf(tempLong);
237495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      result = result.scaleByPowerOfTen(scale);
238495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (isNegative()) result = result.negate();
239495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      return result;
240495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
241495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
242495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
243495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
244495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  protected void compact() {
245495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
246495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int delta = 0;
247495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; delta < precision && bcdBytes[delta] == 0; delta++) ;
248495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (delta == precision) {
249495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        // Number is zero
250495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        setBcdToZero();
251495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        return;
252495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      } else {
253495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        // Remove trailing zeros
254495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        shiftRight(delta);
255495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
256495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
257495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Compute precision
258495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int leading = precision - 1;
259495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (; leading >= 0 && bcdBytes[leading] == 0; leading--) ;
260495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      precision = leading + 1;
261495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
262495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Switch storage mechanism if possible
263495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision <= 16) {
264495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        switchStorage();
265495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
266495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
267495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
268495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (bcdLong == 0L) {
269495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        // Number is zero
270495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        setBcdToZero();
271495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        return;
272495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
273495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
274495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Compact the number (remove trailing zeros)
275495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      int delta = Long.numberOfTrailingZeros(bcdLong) / 4;
276495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong >>>= delta * 4;
277495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      scale += delta;
278495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
279495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Compute precision
280495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4);
281495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
282495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
283495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
284495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  /** Ensure that a byte array of at least 40 digits is allocated. */
285495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private void ensureCapacity() {
286495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    ensureCapacity(40);
287495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
288495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
289495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private void ensureCapacity(int capacity) {
290495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (capacity == 0) return;
29105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    int oldCapacity = usingBytes ? bcdBytes.length : 0;
29205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    if (!usingBytes) {
293495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdBytes = new byte[capacity];
29405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    } else if (oldCapacity < capacity) {
295495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      byte[] bcd1 = new byte[capacity * 2];
29605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity);
297495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdBytes = bcd1;
298495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
29905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    usingBytes = true;
300495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
301495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
302495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
303495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  private void switchStorage() {
304495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
305495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Change from bytes to long
306495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong = 0L;
307495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = precision - 1; i >= 0; i--) {
308495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdLong <<= 4;
309495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdLong |= bcdBytes[i];
310495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
31105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      bcdBytes = null;
312495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      usingBytes = false;
313495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
314495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      // Change from long to bytes
315495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity();
316495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = 0; i < precision; i++) {
317495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdBytes[i] = (byte) (bcdLong & 0xf);
318495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        bcdLong >>>= 4;
319495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
32005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      assert usingBytes;
321495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
322495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
323495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
324495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
32505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  protected void copyBcdFrom(DecimalQuantity _other) {
32605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD) _other;
32705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert    setBcdToZero();
328495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (other.usingBytes) {
329495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      ensureCapacity(other.precision);
330495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision);
331495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
332495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      bcdLong = other.bcdLong;
333495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
334495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
335495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
336495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  /**
337495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
338495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   *
339495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * @return An error message if this instance is invalid, or null if this instance is healthy.
340495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * @deprecated This API is for ICU internal use only.
341495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert * @hide draft / provisional / internal are hidden on Android
342495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   */
343495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Deprecated
344495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  public String checkHealth() {
345495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    if (usingBytes) {
346495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (bcdLong != 0) return "Value in bcdLong but we are in byte mode";
347495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision == 0) return "Zero precision but we are in byte mode";
348495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision > bcdBytes.length) return "Precision exceeds length of byte array";
349495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (getDigitPos(precision - 1) == 0) return "Most significant digit is zero in byte mode";
350495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (getDigitPos(0) == 0) return "Least significant digit is zero in long mode";
351495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = 0; i < precision; i++) {
352495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) >= 10) return "Digit exceeding 10 in byte array";
353495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) < 0) return "Digit below 0 in byte array";
354495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
355495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = precision; i < bcdBytes.length; i++) {
356495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) != 0) return "Nonzero digits outside of range in byte array";
357495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
358495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    } else {
359495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (bcdBytes != null) {
360495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        for (int i = 0; i < bcdBytes.length; i++) {
361495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert          if (bcdBytes[i] != 0) return "Nonzero digits in byte array but we are in long mode";
362495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        }
363495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
364495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision == 0 && bcdLong != 0) return "Value in bcdLong even though precision is zero";
365495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision > 16) return "Precision exceeds length of long";
366495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision != 0 && getDigitPos(precision - 1) == 0)
367495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        return "Most significant digit is zero in long mode";
368495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      if (precision != 0 && getDigitPos(0) == 0)
369495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        return "Least significant digit is zero in long mode";
370495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = 0; i < precision; i++) {
371495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) >= 10) return "Digit exceeding 10 in long";
372495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) < 0) return "Digit below 0 in long (?!)";
373495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
374495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      for (int i = precision; i < 16; i++) {
375495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        if (getDigitPos(i) != 0) return "Nonzero digits outside of range in long";
376495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert      }
377495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    }
378495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
379495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    return null;
380495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
381495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
382495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  /**
38305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert   * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its internal byte array storage mechanism.
384495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   *
385495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * @return true if an internal byte array is being used; false if a long is being used.
386495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   * @deprecated This API is ICU internal only.
387495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert * @hide draft / provisional / internal are hidden on Android
388495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert   */
389495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Deprecated
39005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public boolean isUsingBytes() {
391495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    return usingBytes;
392495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
393495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert
394495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  @Override
395495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  public String toString() {
396495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert    return String.format(
39705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        "<DecimalQuantity %s:%d:%d:%s %s %s>",
39805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        (lOptPos > 1000 ? "999" : String.valueOf(lOptPos)),
399495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        lReqPos,
400495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        rReqPos,
40105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        (rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)),
402495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert        (usingBytes ? "bytes" : "long"),
40305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        toNumberString());
40405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  }
40505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert
40605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert  public String toNumberString() {
40705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      StringBuilder sb = new StringBuilder();
40805fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      if (usingBytes) {
40905fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        for (int i = precision - 1; i >= 0; i--) {
41005fa7802d0874812c234a29745586677ee5837eaFredrik Roubert          sb.append(bcdBytes[i]);
41105fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        }
41205fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      } else {
41305fa7802d0874812c234a29745586677ee5837eaFredrik Roubert        sb.append(Long.toHexString(bcdLong));
41405fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      }
41505fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      sb.append("E");
41605fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      sb.append(scale);
41705fa7802d0874812c234a29745586677ee5837eaFredrik Roubert      return sb.toString();
418495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert  }
419495cb271e305cfb399d463f32210a371198f0abfFredrik Roubert}
420