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