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