]>
Commit | Line | Data |
---|---|---|
1 | // © 2018 and later: Unicode, Inc. and others. | |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
3 | ||
4 | #ifndef __FORMVAL_IMPL_H__ | |
5 | #define __FORMVAL_IMPL_H__ | |
6 | ||
7 | #include "unicode/utypes.h" | |
8 | #if !UCONFIG_NO_FORMATTING | |
9 | ||
10 | // This file contains compliant implementations of FormattedValue which can be | |
11 | // leveraged by ICU formatters. | |
12 | // | |
13 | // Each implementation is defined in its own cpp file in order to split | |
14 | // dependencies more modularly. | |
15 | ||
16 | #include "unicode/formattedvalue.h" | |
17 | #include "capi_helper.h" | |
18 | #include "fphdlimp.h" | |
19 | #include "util.h" | |
20 | #include "uvectr32.h" | |
21 | #include "number_stringbuilder.h" | |
22 | ||
23 | ||
24 | /** | |
25 | * Represents the type of constraint for ConstrainedFieldPosition. | |
26 | * | |
27 | * Constraints are used to control the behavior of iteration in FormattedValue. | |
28 | * | |
29 | * @internal | |
30 | */ | |
31 | typedef enum UCFPosConstraintType { | |
32 | /** | |
33 | * Represents the lack of a constraint. | |
34 | * | |
35 | * This is the value of fConstraint if no "constrain" methods were called. | |
36 | * | |
37 | * @internal | |
38 | */ | |
39 | UCFPOS_CONSTRAINT_NONE = 0, | |
40 | ||
41 | /** | |
42 | * Represents that the field category is constrained. | |
43 | * | |
44 | * This is the value of fConstraint if constraintCategory was called. | |
45 | * | |
46 | * FormattedValue implementations should not change the field category | |
47 | * while this constraint is active. | |
48 | * | |
49 | * @internal | |
50 | */ | |
51 | UCFPOS_CONSTRAINT_CATEGORY, | |
52 | ||
53 | /** | |
54 | * Represents that the field and field category are constrained. | |
55 | * | |
56 | * This is the value of fConstraint if constraintField was called. | |
57 | * | |
58 | * FormattedValue implementations should not change the field or field category | |
59 | * while this constraint is active. | |
60 | * | |
61 | * @internal | |
62 | */ | |
63 | UCFPOS_CONSTRAINT_FIELD | |
64 | } UCFPosConstraintType; | |
65 | ||
66 | ||
67 | U_NAMESPACE_BEGIN | |
68 | ||
69 | ||
70 | /** Implementation using FieldPositionHandler to accept fields. */ | |
71 | class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue { | |
72 | public: | |
73 | ||
74 | /** @param initialFieldCapacity Initially allocate space for this many fields. */ | |
75 | FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status); | |
76 | ||
77 | virtual ~FormattedValueFieldPositionIteratorImpl(); | |
78 | ||
79 | // Implementation of FormattedValue (const): | |
80 | ||
81 | UnicodeString toString(UErrorCode& status) const U_OVERRIDE; | |
82 | UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; | |
83 | Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; | |
84 | UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; | |
85 | ||
86 | // Additional methods used during construction phase only (non-const): | |
87 | ||
88 | FieldPositionIteratorHandler getHandler(UErrorCode& status); | |
89 | void appendString(UnicodeString string, UErrorCode& status); | |
90 | ||
91 | /** | |
92 | * Computes the spans for duplicated values. | |
93 | * For example, if the string has fields: | |
94 | * | |
95 | * ...aa..[b.cc]..d.[bb.e.c]..a.. | |
96 | * | |
97 | * then the spans will be the bracketed regions. | |
98 | * | |
99 | * Assumes that the currently known fields are sorted | |
100 | * and all in the same category. | |
101 | */ | |
102 | void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status); | |
103 | ||
104 | /** | |
105 | * Sorts the fields: start index first, length second. | |
106 | */ | |
107 | void sort(); | |
108 | ||
109 | private: | |
110 | UnicodeString fString; | |
111 | UVector32 fFields; | |
112 | }; | |
113 | ||
114 | ||
115 | class FormattedValueNumberStringBuilderImpl : public UMemory, public FormattedValue { | |
116 | public: | |
117 | ||
118 | FormattedValueNumberStringBuilderImpl(number::impl::Field numericField); | |
119 | ||
120 | virtual ~FormattedValueNumberStringBuilderImpl(); | |
121 | ||
122 | // Implementation of FormattedValue (const): | |
123 | ||
124 | UnicodeString toString(UErrorCode& status) const U_OVERRIDE; | |
125 | UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; | |
126 | Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; | |
127 | UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; | |
128 | ||
129 | inline number::impl::NumberStringBuilder& getStringRef() { | |
130 | return fString; | |
131 | } | |
132 | ||
133 | inline const number::impl::NumberStringBuilder& getStringRef() const { | |
134 | return fString; | |
135 | } | |
136 | ||
137 | private: | |
138 | number::impl::NumberStringBuilder fString; | |
139 | number::impl::Field fNumericField; | |
140 | }; | |
141 | ||
142 | ||
143 | // C API Helpers for FormattedValue | |
144 | // Magic number as ASCII == "UFV" | |
145 | struct UFormattedValueImpl; | |
146 | typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper; | |
147 | struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper { | |
148 | // This pointer should be set by the child class. | |
149 | FormattedValue* fFormattedValue = nullptr; | |
150 | }; | |
151 | ||
152 | ||
153 | /** Boilerplate to check for valid status before dereferencing the fData pointer. */ | |
154 | #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \ | |
155 | if (U_FAILURE(status)) { \ | |
156 | return returnExpression; \ | |
157 | } \ | |
158 | if (fData == nullptr) { \ | |
159 | status = fErrorCode; \ | |
160 | return returnExpression; \ | |
161 | } \ | |
162 | ||
163 | ||
164 | /** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */ | |
165 | #define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \ | |
166 | Name::Name(Name&& src) U_NOEXCEPT \ | |
167 | : fData(src.fData), fErrorCode(src.fErrorCode) { \ | |
168 | src.fData = nullptr; \ | |
169 | src.fErrorCode = U_INVALID_STATE_ERROR; \ | |
170 | } \ | |
171 | Name::~Name() { \ | |
172 | delete fData; \ | |
173 | fData = nullptr; \ | |
174 | } \ | |
175 | Name& Name::operator=(Name&& src) U_NOEXCEPT { \ | |
176 | delete fData; \ | |
177 | fData = src.fData; \ | |
178 | src.fData = nullptr; \ | |
179 | fErrorCode = src.fErrorCode; \ | |
180 | src.fErrorCode = U_INVALID_STATE_ERROR; \ | |
181 | return *this; \ | |
182 | } \ | |
183 | UnicodeString Name::toString(UErrorCode& status) const { \ | |
184 | UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ | |
185 | return fData->toString(status); \ | |
186 | } \ | |
187 | UnicodeString Name::toTempString(UErrorCode& status) const { \ | |
188 | UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ | |
189 | return fData->toTempString(status); \ | |
190 | } \ | |
191 | Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \ | |
192 | UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \ | |
193 | return fData->appendTo(appendable, status); \ | |
194 | } \ | |
195 | UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \ | |
196 | UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \ | |
197 | return fData->nextPosition(cfpos, status); \ | |
198 | } | |
199 | ||
200 | ||
201 | /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */ | |
202 | #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \ | |
203 | U_CAPI CType* U_EXPORT2 \ | |
204 | Prefix ## _openResult (UErrorCode* ec) { \ | |
205 | if (U_FAILURE(*ec)) { \ | |
206 | return nullptr; \ | |
207 | } \ | |
208 | ImplType* impl = new ImplType(); \ | |
209 | if (impl == nullptr) { \ | |
210 | *ec = U_MEMORY_ALLOCATION_ERROR; \ | |
211 | return nullptr; \ | |
212 | } \ | |
213 | return static_cast<HelperType*>(impl)->exportForC(); \ | |
214 | } \ | |
215 | U_DRAFT const UFormattedValue* U_EXPORT2 \ | |
216 | Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \ | |
217 | const ImplType* result = HelperType::validate(uresult, *ec); \ | |
218 | if (U_FAILURE(*ec)) { return nullptr; } \ | |
219 | return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \ | |
220 | } \ | |
221 | U_CAPI void U_EXPORT2 \ | |
222 | Prefix ## _closeResult (CType* uresult) { \ | |
223 | UErrorCode localStatus = U_ZERO_ERROR; \ | |
224 | const ImplType* impl = HelperType::validate(uresult, localStatus); \ | |
225 | delete impl; \ | |
226 | } | |
227 | ||
228 | ||
229 | /** | |
230 | * Implementation of the standard methods for a UFormattedValue "subclass" C API. | |
231 | * @param CPPType The public C++ type, like FormattedList | |
232 | * @param CType The public C type, like UFormattedList | |
233 | * @param ImplType A name to use for the implementation class | |
234 | * @param HelperType A name to use for the "mixin" typedef for C API conversion | |
235 | * @param Prefix The C API prefix, like ulistfmt | |
236 | * @param MagicNumber A unique 32-bit number to use to identify this type | |
237 | */ | |
238 | #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \ | |
239 | U_NAMESPACE_BEGIN \ | |
240 | class ImplType; \ | |
241 | typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \ | |
242 | class ImplType : public UFormattedValueImpl, public HelperType { \ | |
243 | public: \ | |
244 | ImplType(); \ | |
245 | ~ImplType(); \ | |
246 | CPPType fImpl; \ | |
247 | }; \ | |
248 | ImplType::ImplType() { \ | |
249 | fFormattedValue = &fImpl; \ | |
250 | } \ | |
251 | ImplType::~ImplType() {} \ | |
252 | U_NAMESPACE_END \ | |
253 | UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) | |
254 | ||
255 | ||
256 | U_NAMESPACE_END | |
257 | ||
258 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
259 | #endif // __FORMVAL_IMPL_H__ |