1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
7 #ifndef __NUMBER_MODIFIERS_H__
8 #define __NUMBER_MODIFIERS_H__
12 #include "unicode/uniset.h"
13 #include "unicode/simpleformatter.h"
14 #include "standardplural.h"
15 #include "number_stringbuilder.h"
16 #include "number_types.h"
18 U_NAMESPACE_BEGIN
namespace number
{
22 * The canonical implementation of {@link Modifier}, containing a prefix and suffix string.
23 * TODO: This is not currently being used by real code and could be removed.
25 class U_I18N_API ConstantAffixModifier
: public Modifier
, public UObject
{
27 ConstantAffixModifier(const UnicodeString
&prefix
, const UnicodeString
&suffix
, Field field
,
29 : fPrefix(prefix
), fSuffix(suffix
), fField(field
), fStrong(strong
) {}
31 int32_t apply(NumberStringBuilder
&output
, int32_t leftIndex
, int32_t rightIndex
,
32 UErrorCode
&status
) const U_OVERRIDE
;
34 int32_t getPrefixLength() const U_OVERRIDE
;
36 int32_t getCodePointCount() const U_OVERRIDE
;
38 bool isStrong() const U_OVERRIDE
;
40 bool containsField(UNumberFormatFields field
) const U_OVERRIDE
;
42 void getParameters(Parameters
& output
) const U_OVERRIDE
;
44 bool semanticallyEquivalent(const Modifier
& other
) const U_OVERRIDE
;
47 UnicodeString fPrefix
;
48 UnicodeString fSuffix
;
54 * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter}
57 class U_I18N_API SimpleModifier
: public Modifier
, public UMemory
{
59 SimpleModifier(const SimpleFormatter
&simpleFormatter
, Field field
, bool strong
);
61 SimpleModifier(const SimpleFormatter
&simpleFormatter
, Field field
, bool strong
,
62 const Modifier::Parameters parameters
);
64 // Default constructor for LongNameHandler.h
67 int32_t apply(NumberStringBuilder
&output
, int32_t leftIndex
, int32_t rightIndex
,
68 UErrorCode
&status
) const U_OVERRIDE
;
70 int32_t getPrefixLength() const U_OVERRIDE
;
72 int32_t getCodePointCount() const U_OVERRIDE
;
74 bool isStrong() const U_OVERRIDE
;
76 bool containsField(UNumberFormatFields field
) const U_OVERRIDE
;
78 void getParameters(Parameters
& output
) const U_OVERRIDE
;
80 bool semanticallyEquivalent(const Modifier
& other
) const U_OVERRIDE
;
83 * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
84 * NumberStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
87 * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
88 * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the
92 * This is well-defined only for patterns with exactly one argument.
95 * The StringBuilder containing the value argument.
97 * The left index of the value within the string builder.
99 * The right index of the value within the string builder.
100 * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
103 formatAsPrefixSuffix(NumberStringBuilder
& result
, int32_t startIndex
, int32_t endIndex
,
104 UErrorCode
& status
) const;
107 * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
108 * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other.
111 * Applies the compiled two-argument pattern to the NumberStringBuilder.
114 * This method is optimized for the case where the prefix and suffix are often empty, such as
115 * in the range pattern like "{0}-{1}".
118 formatTwoArgPattern(const SimpleFormatter
& compiled
, NumberStringBuilder
& result
,
119 int32_t index
, int32_t* outPrefixLength
, int32_t* outSuffixLength
,
120 Field field
, UErrorCode
& status
);
123 UnicodeString fCompiledPattern
;
125 bool fStrong
= false;
126 int32_t fPrefixLength
= 0;
127 int32_t fSuffixOffset
= -1;
128 int32_t fSuffixLength
= 0;
129 Modifier::Parameters fParameters
;
133 * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
134 * based on the contents of two {@link NumberStringBuilder} instances (one for the prefix, one for the suffix).
136 class U_I18N_API ConstantMultiFieldModifier
: public Modifier
, public UMemory
{
138 ConstantMultiFieldModifier(
139 const NumberStringBuilder
&prefix
,
140 const NumberStringBuilder
&suffix
,
143 const Modifier::Parameters parameters
)
146 fOverwrite(overwrite
),
148 fParameters(parameters
) {}
150 ConstantMultiFieldModifier(
151 const NumberStringBuilder
&prefix
,
152 const NumberStringBuilder
&suffix
,
157 fOverwrite(overwrite
),
160 int32_t apply(NumberStringBuilder
&output
, int32_t leftIndex
, int32_t rightIndex
,
161 UErrorCode
&status
) const U_OVERRIDE
;
163 int32_t getPrefixLength() const U_OVERRIDE
;
165 int32_t getCodePointCount() const U_OVERRIDE
;
167 bool isStrong() const U_OVERRIDE
;
169 bool containsField(UNumberFormatFields field
) const U_OVERRIDE
;
171 void getParameters(Parameters
& output
) const U_OVERRIDE
;
173 bool semanticallyEquivalent(const Modifier
& other
) const U_OVERRIDE
;
176 // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by
177 // value and is treated internally as immutable.
178 NumberStringBuilder fPrefix
;
179 NumberStringBuilder fSuffix
;
182 Modifier::Parameters fParameters
;
185 /** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
186 class U_I18N_API CurrencySpacingEnabledModifier
: public ConstantMultiFieldModifier
{
188 /** Safe code path */
189 CurrencySpacingEnabledModifier(
190 const NumberStringBuilder
&prefix
,
191 const NumberStringBuilder
&suffix
,
194 const DecimalFormatSymbols
&symbols
,
197 int32_t apply(NumberStringBuilder
&output
, int32_t leftIndex
, int32_t rightIndex
,
198 UErrorCode
&status
) const U_OVERRIDE
;
200 /** Unsafe code path */
202 applyCurrencySpacing(NumberStringBuilder
&output
, int32_t prefixStart
, int32_t prefixLen
,
203 int32_t suffixStart
, int32_t suffixLen
, const DecimalFormatSymbols
&symbols
,
207 UnicodeSet fAfterPrefixUnicodeSet
;
208 UnicodeString fAfterPrefixInsert
;
209 UnicodeSet fBeforeSuffixUnicodeSet
;
210 UnicodeString fBeforeSuffixInsert
;
217 IN_CURRENCY
, IN_NUMBER
220 /** Unsafe code path */
221 static int32_t applyCurrencySpacingAffix(NumberStringBuilder
&output
, int32_t index
, EAffix affix
,
222 const DecimalFormatSymbols
&symbols
, UErrorCode
&status
);
225 getUnicodeSet(const DecimalFormatSymbols
&symbols
, EPosition position
, EAffix affix
,
229 getInsertString(const DecimalFormatSymbols
&symbols
, EAffix affix
, UErrorCode
&status
);
232 /** A Modifier that does not do anything. */
233 class U_I18N_API EmptyModifier
: public Modifier
, public UMemory
{
235 explicit EmptyModifier(bool isStrong
) : fStrong(isStrong
) {}
237 int32_t apply(NumberStringBuilder
&output
, int32_t leftIndex
, int32_t rightIndex
,
238 UErrorCode
&status
) const U_OVERRIDE
{
246 int32_t getPrefixLength() const U_OVERRIDE
{
250 int32_t getCodePointCount() const U_OVERRIDE
{
254 bool isStrong() const U_OVERRIDE
{
258 bool containsField(UNumberFormatFields field
) const U_OVERRIDE
{
263 void getParameters(Parameters
& output
) const U_OVERRIDE
{
264 output
.obj
= nullptr;
267 bool semanticallyEquivalent(const Modifier
& other
) const U_OVERRIDE
{
268 return other
.getCodePointCount() == 0;
276 * This implementation of ModifierStore adopts Modifer pointers.
278 class U_I18N_API AdoptingModifierStore
: public ModifierStore
, public UMemory
{
280 virtual ~AdoptingModifierStore();
282 static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL
= StandardPlural::OTHER
;
284 AdoptingModifierStore() = default;
287 AdoptingModifierStore(const AdoptingModifierStore
&other
) = delete;
290 * Sets the Modifier with the specified signum and plural form.
292 void adoptModifier(int8_t signum
, StandardPlural::Form plural
, const Modifier
*mod
) {
293 U_ASSERT(mods
[getModIndex(signum
, plural
)] == nullptr);
294 mods
[getModIndex(signum
, plural
)] = mod
;
298 * Sets the Modifier with the specified signum.
299 * The modifier will apply to all plural forms.
301 void adoptModifierWithoutPlural(int8_t signum
, const Modifier
*mod
) {
302 U_ASSERT(mods
[getModIndex(signum
, DEFAULT_STANDARD_PLURAL
)] == nullptr);
303 mods
[getModIndex(signum
, DEFAULT_STANDARD_PLURAL
)] = mod
;
306 /** Returns a reference to the modifier; no ownership change. */
307 const Modifier
*getModifier(int8_t signum
, StandardPlural::Form plural
) const U_OVERRIDE
{
308 const Modifier
* modifier
= mods
[getModIndex(signum
, plural
)];
309 if (modifier
== nullptr && plural
!= DEFAULT_STANDARD_PLURAL
) {
310 modifier
= mods
[getModIndex(signum
, DEFAULT_STANDARD_PLURAL
)];
315 /** Returns a reference to the modifier; no ownership change. */
316 const Modifier
*getModifierWithoutPlural(int8_t signum
) const {
317 return mods
[getModIndex(signum
, DEFAULT_STANDARD_PLURAL
)];
321 // NOTE: mods is zero-initialized (to nullptr)
322 const Modifier
*mods
[3 * StandardPlural::COUNT
] = {};
324 inline static int32_t getModIndex(int8_t signum
, StandardPlural::Form plural
) {
325 U_ASSERT(signum
>= -1 && signum
<= 1);
326 U_ASSERT(plural
>= 0 && plural
< StandardPlural::COUNT
);
327 return static_cast<int32_t>(plural
) * 3 + (signum
+ 1);
332 } // namespace number
336 #endif //__NUMBER_MODIFIERS_H__
338 #endif /* #if !UCONFIG_NO_FORMATTING */