1 // © 2018 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 #ifndef __NUMBER_MAPPER_H__ 8 #define __NUMBER_MAPPER_H__ 9 10 #include <atomic> 11 #include "number_types.h" 12 #include "unicode/currpinf.h" 13 #include "standardplural.h" 14 #include "number_patternstring.h" 15 #include "number_currencysymbols.h" 16 #include "numparse_impl.h" 17 18 U_NAMESPACE_BEGIN 19 namespace number::impl { 20 21 class AutoAffixPatternProvider; 22 class CurrencyPluralInfoAffixProvider; 23 24 25 class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory { 26 public: isBogus()27 bool isBogus() const { 28 return fBogus; 29 } 30 setToBogus()31 void setToBogus() { 32 fBogus = true; 33 } 34 35 void setTo(const DecimalFormatProperties& properties, UErrorCode& status); 36 37 // AffixPatternProvider Methods: 38 39 char16_t charAt(int32_t flags, int32_t i) const override; 40 41 int32_t length(int32_t flags) const override; 42 43 UnicodeString getString(int32_t flags) const override; 44 45 bool hasCurrencySign() const override; 46 47 bool positiveHasPlusSign() const override; 48 49 bool hasNegativeSubpattern() const override; 50 51 bool negativeHasMinusSign() const override; 52 53 bool containsSymbolType(AffixPatternType, UErrorCode&) const override; 54 55 bool hasBody() const override; 56 57 bool currencyAsDecimal() const override; 58 59 private: 60 UnicodeString posPrefix; 61 UnicodeString posSuffix; 62 UnicodeString negPrefix; 63 UnicodeString negSuffix; 64 bool isCurrencyPattern; 65 bool fCurrencyAsDecimal; 66 67 PropertiesAffixPatternProvider() = default; // puts instance in valid but undefined state 68 69 const UnicodeString& getStringInternal(int32_t flags) const; 70 71 bool fBogus{true}; 72 73 friend class AutoAffixPatternProvider; 74 friend class CurrencyPluralInfoAffixProvider; 75 }; 76 77 78 class CurrencyPluralInfoAffixProvider : public AffixPatternProvider, public UMemory { 79 public: isBogus()80 bool isBogus() const { 81 return fBogus; 82 } 83 setToBogus()84 void setToBogus() { 85 fBogus = true; 86 } 87 88 void setTo(const CurrencyPluralInfo& cpi, const DecimalFormatProperties& properties, 89 UErrorCode& status); 90 91 // AffixPatternProvider Methods: 92 93 char16_t charAt(int32_t flags, int32_t i) const override; 94 95 int32_t length(int32_t flags) const override; 96 97 UnicodeString getString(int32_t flags) const override; 98 99 bool hasCurrencySign() const override; 100 101 bool positiveHasPlusSign() const override; 102 103 bool hasNegativeSubpattern() const override; 104 105 bool negativeHasMinusSign() const override; 106 107 bool containsSymbolType(AffixPatternType, UErrorCode&) const override; 108 109 bool hasBody() const override; 110 111 bool currencyAsDecimal() const override; 112 113 private: 114 PropertiesAffixPatternProvider affixesByPlural[StandardPlural::COUNT]; 115 116 CurrencyPluralInfoAffixProvider() = default; 117 118 bool fBogus{true}; 119 120 friend class AutoAffixPatternProvider; 121 }; 122 123 124 class AutoAffixPatternProvider { 125 public: 126 inline AutoAffixPatternProvider() = default; 127 AutoAffixPatternProvider(const DecimalFormatProperties & properties,UErrorCode & status)128 inline AutoAffixPatternProvider(const DecimalFormatProperties& properties, UErrorCode& status) { 129 setTo(properties, status); 130 } 131 setTo(const DecimalFormatProperties & properties,UErrorCode & status)132 inline void setTo(const DecimalFormatProperties& properties, UErrorCode& status) { 133 if (properties.currencyPluralInfo.fPtr.isNull()) { 134 propertiesAPP.setTo(properties, status); 135 currencyPluralInfoAPP.setToBogus(); 136 } else { 137 propertiesAPP.setToBogus(); 138 currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, properties, status); 139 } 140 } 141 setTo(const AffixPatternProvider * provider,UErrorCode & status)142 inline void setTo(const AffixPatternProvider* provider, UErrorCode& status) { 143 if (const auto* ptr = dynamic_cast<const PropertiesAffixPatternProvider*>(provider)) { 144 propertiesAPP = *ptr; 145 } else if (const auto* ptr = dynamic_cast<const CurrencyPluralInfoAffixProvider*>(provider)) { 146 currencyPluralInfoAPP = *ptr; 147 } else { 148 status = U_INTERNAL_PROGRAM_ERROR; 149 } 150 } 151 get()152 inline const AffixPatternProvider& get() const { 153 if (!currencyPluralInfoAPP.isBogus()) { 154 return currencyPluralInfoAPP; 155 } else { 156 return propertiesAPP; 157 } 158 } 159 160 private: 161 PropertiesAffixPatternProvider propertiesAPP; 162 CurrencyPluralInfoAffixProvider currencyPluralInfoAPP; 163 }; 164 165 166 /** 167 * A struct for ownership of a few objects needed for formatting. 168 */ 169 struct DecimalFormatWarehouse : public UMemory { 170 AutoAffixPatternProvider affixProvider; 171 LocalPointer<PluralRules> rules; 172 }; 173 174 175 /** 176 * Internal fields for DecimalFormat. 177 * TODO: Make some of these fields by value instead of by LocalPointer? 178 */ 179 struct DecimalFormatFields : public UMemory { 180 DecimalFormatFieldsDecimalFormatFields181 DecimalFormatFields() {} 182 DecimalFormatFieldsDecimalFormatFields183 DecimalFormatFields(const DecimalFormatProperties& propsToCopy) 184 : properties(propsToCopy) {} 185 186 /** The property bag corresponding to user-specified settings and settings from the pattern string. */ 187 DecimalFormatProperties properties; 188 189 /** The symbols for the current locale. */ 190 LocalPointer<const DecimalFormatSymbols> symbols; 191 192 /** 193 * The pre-computed formatter object. Setters cause this to be re-computed atomically. The {@link 194 * #format} method uses the formatter directly without needing to synchronize. 195 */ 196 LocalizedNumberFormatter formatter; 197 198 /** The lazy-computed parser for .parse() */ 199 std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {}; 200 201 /** The lazy-computed parser for .parseCurrency() */ 202 std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {}; 203 204 /** Small object ownership warehouse for the formatter and parser */ 205 DecimalFormatWarehouse warehouse; 206 207 /** The effective properties as exported from the formatter object. Used by some getters. */ 208 DecimalFormatProperties exportedProperties; 209 210 // Data for fastpath 211 bool canUseFastFormat = false; 212 struct FastFormatData { 213 char16_t cpZero; 214 char16_t cpGroupingSeparator; 215 char16_t cpMinusSign; 216 int8_t minInt; 217 int8_t maxInt; 218 } fastData; 219 }; 220 221 222 /** 223 * Utilities for converting between a DecimalFormatProperties and a MacroProps. 224 */ 225 class NumberPropertyMapper { 226 public: 227 /** Convenience method to create a NumberFormatter directly from Properties. */ 228 static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, 229 const DecimalFormatSymbols& symbols, 230 DecimalFormatWarehouse& warehouse, UErrorCode& status); 231 232 /** Convenience method to create a NumberFormatter directly from Properties. */ 233 static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, 234 const DecimalFormatSymbols& symbols, 235 DecimalFormatWarehouse& warehouse, 236 DecimalFormatProperties& exportedProperties, 237 UErrorCode& status); 238 239 /** 240 * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} 241 * object. In other words, maps Properties to MacroProps. This function is used by the 242 * JDK-compatibility API to call into the ICU 60 fluent number formatting pipeline. 243 * 244 * @param properties 245 * The property bag to be mapped. 246 * @param symbols 247 * The symbols associated with the property bag. 248 * @param exportedProperties 249 * A property bag in which to store validated properties. Used by some DecimalFormat 250 * getters. 251 * @return A new MacroProps containing all of the information in the Properties. 252 */ 253 static MacroProps oldToNew(const DecimalFormatProperties& properties, 254 const DecimalFormatSymbols& symbols, DecimalFormatWarehouse& warehouse, 255 DecimalFormatProperties* exportedProperties, UErrorCode& status); 256 }; 257 258 } // namespace number::impl 259 U_NAMESPACE_END 260 261 #endif //__NUMBER_MAPPER_H__ 262 #endif /* #if !UCONFIG_NO_FORMATTING */ 263