1 // © 2018 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 package com.ibm.icu.number; 4 5 import java.io.IOException; 6 import java.math.BigDecimal; 7 import java.text.AttributedCharacterIterator; 8 import java.util.Arrays; 9 10 import com.ibm.icu.impl.FormattedStringBuilder; 11 import com.ibm.icu.impl.FormattedValueStringBuilderImpl; 12 import com.ibm.icu.impl.number.DecimalQuantity; 13 import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityResult; 14 import com.ibm.icu.text.ConstrainedFieldPosition; 15 import com.ibm.icu.text.FormattedValue; 16 import com.ibm.icu.text.PluralRules.IFixedDecimal; 17 import com.ibm.icu.util.ICUUncheckedIOException; 18 19 /** 20 * The result of a number range formatting operation. This class allows the result to be exported in several data types, 21 * including a String, an AttributedCharacterIterator, and a BigDecimal. 22 * 23 * Instances of this class are immutable and thread-safe. 24 * 25 * @author sffc 26 * @stable ICU 63 27 * @see NumberRangeFormatter 28 */ 29 public class FormattedNumberRange implements FormattedValue { 30 final FormattedStringBuilder string; 31 final DecimalQuantity quantity1; 32 final DecimalQuantity quantity2; 33 final RangeIdentityResult identityResult; 34 FormattedNumberRange(FormattedStringBuilder string, DecimalQuantity quantity1, DecimalQuantity quantity2, RangeIdentityResult identityResult)35 FormattedNumberRange(FormattedStringBuilder string, DecimalQuantity quantity1, DecimalQuantity quantity2, 36 RangeIdentityResult identityResult) { 37 this.string = string; 38 this.quantity1 = quantity1; 39 this.quantity2 = quantity2; 40 this.identityResult = identityResult; 41 } 42 43 /** 44 * {@inheritDoc} 45 * 46 * @stable ICU 63 47 */ 48 @Override toString()49 public String toString() { 50 return string.toString(); 51 } 52 53 /** 54 * {@inheritDoc} 55 * 56 * @stable ICU 63 57 */ 58 @Override appendTo(A appendable)59 public <A extends Appendable> A appendTo(A appendable) { 60 try { 61 appendable.append(string); 62 } catch (IOException e) { 63 // Throw as an unchecked exception to avoid users needing try/catch 64 throw new ICUUncheckedIOException(e); 65 } 66 return appendable; 67 } 68 69 /** 70 * {@inheritDoc} 71 * 72 * @stable ICU 64 73 */ 74 @Override charAt(int index)75 public char charAt(int index) { 76 return string.charAt(index); 77 } 78 79 /** 80 * {@inheritDoc} 81 * 82 * @stable ICU 64 83 */ 84 @Override length()85 public int length() { 86 return string.length(); 87 } 88 89 /** 90 * {@inheritDoc} 91 * 92 * @stable ICU 64 93 */ 94 @Override subSequence(int start, int end)95 public CharSequence subSequence(int start, int end) { 96 return string.subString(start, end); 97 } 98 99 /** 100 * {@inheritDoc} 101 * 102 * @stable ICU 64 103 */ 104 @Override nextPosition(ConstrainedFieldPosition cfpos)105 public boolean nextPosition(ConstrainedFieldPosition cfpos) { 106 return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null); 107 } 108 109 /** 110 * {@inheritDoc} 111 * 112 * @stable ICU 63 113 */ 114 @Override toCharacterIterator()115 public AttributedCharacterIterator toCharacterIterator() { 116 return FormattedValueStringBuilderImpl.toCharacterIterator(string, null); 117 } 118 119 /** 120 * Export the first formatted number as a BigDecimal. This endpoint is useful for obtaining the exact number being 121 * printed after scaling and rounding have been applied by the number range formatting pipeline. 122 * 123 * @return A BigDecimal representation of the first formatted number. 124 * @stable ICU 63 125 * @see NumberRangeFormatter 126 * @see #getSecondBigDecimal 127 */ getFirstBigDecimal()128 public BigDecimal getFirstBigDecimal() { 129 return quantity1.toBigDecimal(); 130 } 131 132 /** 133 * Export the second formatted number as a BigDecimal. This endpoint is useful for obtaining the exact number being 134 * printed after scaling and rounding have been applied by the number range formatting pipeline. 135 * 136 * @return A BigDecimal representation of the second formatted number. 137 * @stable ICU 63 138 * @see NumberRangeFormatter 139 * @see #getFirstBigDecimal 140 */ getSecondBigDecimal()141 public BigDecimal getSecondBigDecimal() { 142 return quantity2.toBigDecimal(); 143 } 144 145 /** 146 * Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was 147 * used. For example, if the first and second number were the same either before or after rounding occurred, an 148 * identity fallback was used. 149 * 150 * @return A RangeIdentityType indicating the resulting identity situation in the formatted number range. 151 * @stable ICU 63 152 * @see NumberRangeFormatter 153 * @see NumberRangeFormatter.RangeIdentityFallback 154 */ getIdentityResult()155 public RangeIdentityResult getIdentityResult() { 156 return identityResult; 157 } 158 159 /** 160 * {@inheritDoc} 161 * 162 * @stable ICU 63 163 */ 164 @Override hashCode()165 public int hashCode() { 166 // FormattedStringBuilder and BigDecimal are mutable, so we can't call 167 // #equals() or #hashCode() on them directly. 168 return Arrays.hashCode(string.toCharArray()) ^ Arrays.hashCode(string.toFieldArray()) 169 ^ quantity1.toBigDecimal().hashCode() ^ quantity2.toBigDecimal().hashCode(); 170 } 171 172 /** 173 * {@inheritDoc} 174 * 175 * @stable ICU 63 176 */ 177 @Override equals(Object other)178 public boolean equals(Object other) { 179 if (this == other) 180 return true; 181 if (other == null) 182 return false; 183 if (!(other instanceof FormattedNumberRange)) 184 return false; 185 // FormattedStringBuilder and BigDecimal are mutable, so we can't call 186 // #equals() or #hashCode() on them directly. 187 FormattedNumberRange _other = (FormattedNumberRange) other; 188 return string.contentEquals(_other.string) 189 && quantity1.toBigDecimal().equals(_other.quantity1.toBigDecimal()) 190 && quantity2.toBigDecimal().equals(_other.quantity2.toBigDecimal()); 191 } 192 193 /** 194 * @internal 195 * @deprecated This API is ICU internal only. 196 */ 197 @Deprecated getFirstFixedDecimal()198 public IFixedDecimal getFirstFixedDecimal() { 199 return quantity1; 200 } 201 202 /** 203 * @internal 204 * @deprecated This API is ICU internal only. 205 */ 206 @Deprecated getSecondFixedDecimal()207 public IFixedDecimal getSecondFixedDecimal() { 208 return quantity2; 209 } 210 } 211