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