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 "formatted_string_builder.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 | /** |
71 | * Implementation of FormattedValue using FieldPositionHandler to accept fields. |
72 | */ |
73 | class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue { |
74 | public: |
75 | |
76 | /** @param initialFieldCapacity Initially allocate space for this many fields. */ |
77 | FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status); |
78 | |
79 | virtual ~FormattedValueFieldPositionIteratorImpl(); |
80 | |
81 | // Implementation of FormattedValue (const): |
82 | |
83 | UnicodeString toString(UErrorCode& status) const U_OVERRIDE; |
84 | UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; |
85 | Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; |
86 | UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; |
87 | |
88 | // Additional methods used during construction phase only (non-const): |
89 | |
90 | FieldPositionIteratorHandler getHandler(UErrorCode& status); |
91 | void appendString(UnicodeString string, UErrorCode& status); |
92 | |
93 | /** |
94 | * Computes the spans for duplicated values. |
95 | * For example, if the string has fields: |
96 | * |
97 | * ...aa..[b.cc]..d.[bb.e.c]..a.. |
98 | * |
99 | * then the spans will be the bracketed regions. |
100 | * |
101 | * Assumes that the currently known fields are sorted |
102 | * and all in the same category. |
103 | */ |
104 | void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status); |
105 | |
106 | /** |
107 | * Sorts the fields: start index first, length second. |
108 | */ |
109 | void sort(); |
110 | |
111 | private: |
112 | UnicodeString fString; |
113 | UVector32 fFields; |
114 | }; |
115 | |
116 | |
117 | /** |
118 | * Implementation of FormattedValue based on FormattedStringBuilder. |
119 | * |
120 | * The implementation currently revolves around numbers and number fields. |
121 | * However, it can be generalized in the future when there is a need. |
122 | * |
123 | * @author sffc (Shane Carr) |
124 | */ |
125 | // Exported as U_I18N_API for tests |
126 | class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue { |
127 | public: |
128 | |
129 | FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField); |
130 | |
131 | virtual ~FormattedValueStringBuilderImpl(); |
132 | |
133 | // Implementation of FormattedValue (const): |
134 | |
135 | UnicodeString toString(UErrorCode& status) const U_OVERRIDE; |
136 | UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; |
137 | Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; |
138 | UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; |
139 | |
140 | // Additional helper functions: |
141 | UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const; |
142 | void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; |
143 | inline FormattedStringBuilder& getStringRef() { |
144 | return fString; |
145 | } |
146 | inline const FormattedStringBuilder& getStringRef() const { |
147 | return fString; |
148 | } |
149 | |
150 | private: |
151 | FormattedStringBuilder fString; |
152 | FormattedStringBuilder::Field fNumericField; |
153 | |
154 | bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const; |
155 | static bool isIntOrGroup(FormattedStringBuilder::Field field); |
156 | static bool isNumericField(FormattedStringBuilder::Field field); |
157 | int32_t trimBack(int32_t limit) const; |
158 | int32_t trimFront(int32_t start) const; |
159 | }; |
160 | |
161 | |
162 | // C API Helpers for FormattedValue |
163 | // Magic number as ASCII == "UFV" |
164 | struct UFormattedValueImpl; |
165 | typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper; |
166 | struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper { |
167 | // This pointer should be set by the child class. |
168 | FormattedValue* fFormattedValue = nullptr; |
169 | }; |
170 | |
171 | |
172 | /** Boilerplate to check for valid status before dereferencing the fData pointer. */ |
173 | #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \ |
174 | if (U_FAILURE(status)) { \ |
175 | return returnExpression; \ |
176 | } \ |
177 | if (fData == nullptr) { \ |
178 | status = fErrorCode; \ |
179 | return returnExpression; \ |
180 | } \ |
181 | |
182 | |
183 | /** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */ |
184 | #define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \ |
185 | Name::Name(Name&& src) U_NOEXCEPT \ |
186 | : fData(src.fData), fErrorCode(src.fErrorCode) { \ |
187 | src.fData = nullptr; \ |
188 | src.fErrorCode = U_INVALID_STATE_ERROR; \ |
189 | } \ |
190 | Name::~Name() { \ |
191 | delete fData; \ |
192 | fData = nullptr; \ |
193 | } \ |
194 | Name& Name::operator=(Name&& src) U_NOEXCEPT { \ |
195 | delete fData; \ |
196 | fData = src.fData; \ |
197 | src.fData = nullptr; \ |
198 | fErrorCode = src.fErrorCode; \ |
199 | src.fErrorCode = U_INVALID_STATE_ERROR; \ |
200 | return *this; \ |
201 | } \ |
202 | UnicodeString Name::toString(UErrorCode& status) const { \ |
203 | UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ |
204 | return fData->toString(status); \ |
205 | } \ |
206 | UnicodeString Name::toTempString(UErrorCode& status) const { \ |
207 | UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ |
208 | return fData->toTempString(status); \ |
209 | } \ |
210 | Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \ |
211 | UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \ |
212 | return fData->appendTo(appendable, status); \ |
213 | } \ |
214 | UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \ |
215 | UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \ |
216 | return fData->nextPosition(cfpos, status); \ |
217 | } |
218 | |
219 | |
220 | /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */ |
221 | #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \ |
222 | U_CAPI CType* U_EXPORT2 \ |
223 | Prefix ## _openResult (UErrorCode* ec) { \ |
224 | if (U_FAILURE(*ec)) { \ |
225 | return nullptr; \ |
226 | } \ |
227 | ImplType* impl = new ImplType(); \ |
228 | if (impl == nullptr) { \ |
229 | *ec = U_MEMORY_ALLOCATION_ERROR; \ |
230 | return nullptr; \ |
231 | } \ |
232 | return static_cast<HelperType*>(impl)->exportForC(); \ |
233 | } \ |
234 | U_DRAFT const UFormattedValue* U_EXPORT2 \ |
235 | Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \ |
236 | const ImplType* result = HelperType::validate(uresult, *ec); \ |
237 | if (U_FAILURE(*ec)) { return nullptr; } \ |
238 | return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \ |
239 | } \ |
240 | U_CAPI void U_EXPORT2 \ |
241 | Prefix ## _closeResult (CType* uresult) { \ |
242 | UErrorCode localStatus = U_ZERO_ERROR; \ |
243 | const ImplType* impl = HelperType::validate(uresult, localStatus); \ |
244 | delete impl; \ |
245 | } |
246 | |
247 | |
248 | /** |
249 | * Implementation of the standard methods for a UFormattedValue "subclass" C API. |
250 | * @param CPPType The public C++ type, like FormattedList |
251 | * @param CType The public C type, like UFormattedList |
252 | * @param ImplType A name to use for the implementation class |
253 | * @param HelperType A name to use for the "mixin" typedef for C API conversion |
254 | * @param Prefix The C API prefix, like ulistfmt |
255 | * @param MagicNumber A unique 32-bit number to use to identify this type |
256 | */ |
257 | #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \ |
258 | U_NAMESPACE_BEGIN \ |
259 | class ImplType; \ |
260 | typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \ |
261 | class ImplType : public UFormattedValueImpl, public HelperType { \ |
262 | public: \ |
263 | ImplType(); \ |
264 | ~ImplType(); \ |
265 | CPPType fImpl; \ |
266 | }; \ |
267 | ImplType::ImplType() { \ |
268 | fFormattedValue = &fImpl; \ |
269 | } \ |
270 | ImplType::~ImplType() {} \ |
271 | U_NAMESPACE_END \ |
272 | UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) |
273 | |
274 | |
275 | U_NAMESPACE_END |
276 | |
277 | #endif /* #if !UCONFIG_NO_FORMATTING */ |
278 | #endif // __FORMVAL_IMPL_H__ |
279 | |