• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * TODO(ICU-20897): This class is unused. If it is not needed when fixing ICU-20897,
74  * it should be deleted.
75  */
76 class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
77 public:
78 
79     /** @param initialFieldCapacity Initially allocate space for this many fields. */
80     FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status);
81 
82     virtual ~FormattedValueFieldPositionIteratorImpl();
83 
84     // Implementation of FormattedValue (const):
85 
86     UnicodeString toString(UErrorCode& status) const override;
87     UnicodeString toTempString(UErrorCode& status) const override;
88     Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override;
89     UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override;
90 
91     // Additional methods used during construction phase only (non-const):
92 
93     FieldPositionIteratorHandler getHandler(UErrorCode& status);
94     void appendString(UnicodeString string, UErrorCode& status);
95 
96     /**
97      * Computes the spans for duplicated values.
98      * For example, if the string has fields:
99      *
100      *     ...aa..[b.cc]..d.[bb.e.c]..a..
101      *
102      * then the spans will be the bracketed regions.
103      *
104      * Assumes that the currently known fields are sorted
105      * and all in the same category.
106      */
107     void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status);
108 
109     /**
110      * Sorts the fields: start index first, length second.
111      */
112     void sort();
113 
114 private:
115     UnicodeString fString;
116     UVector32 fFields;
117 };
118 
119 
120 // Internal struct that must be exported for MSVC
121 struct U_I18N_API SpanInfo {
122     UFieldCategory category;
123     int32_t spanValue;
124     int32_t start;
125     int32_t length;
126 };
127 
128 // Export an explicit template instantiation of the MaybeStackArray that
129 //    is used as a data member of CEBuffer.
130 //
131 //    When building DLLs for Windows this is required even though
132 //    no direct access to the MaybeStackArray leaks out of the i18n library.
133 //
134 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
135 //
136 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
137 template class U_I18N_API MaybeStackArray<SpanInfo, 8>;
138 #endif
139 
140 /**
141  * Implementation of FormattedValue based on FormattedStringBuilder.
142  *
143  * The implementation currently revolves around numbers and number fields.
144  * However, it can be generalized in the future when there is a need.
145  *
146  * @author sffc (Shane Carr)
147  */
148 // Exported as U_I18N_API for tests
149 class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
150 public:
151 
152     FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
153 
154     virtual ~FormattedValueStringBuilderImpl();
155 
156     FormattedValueStringBuilderImpl(FormattedValueStringBuilderImpl&&) = default;
157     FormattedValueStringBuilderImpl& operator=(FormattedValueStringBuilderImpl&&) = default;
158 
159     // Implementation of FormattedValue (const):
160 
161     UnicodeString toString(UErrorCode& status) const override;
162     UnicodeString toTempString(UErrorCode& status) const override;
163     Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override;
164     UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override;
165 
166     // Additional helper functions:
167     UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
168     void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
getStringRef()169     inline FormattedStringBuilder& getStringRef() {
170         return fString;
171     }
getStringRef()172     inline const FormattedStringBuilder& getStringRef() const {
173         return fString;
174     }
175     void resetString();
176 
177     /**
178      * Adds additional metadata used for span fields.
179      *
180      * category: the category to use for the span field.
181      * spanValue: the value of the span field: index of the list item, for example.
182      * start: the start position within the string of the span. -1 if unknown.
183      * length: the length of the span, used to split adjacent fields.
184      */
185     void appendSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
186     void prependSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
187 
188 private:
189     FormattedStringBuilder fString;
190     FormattedStringBuilder::Field fNumericField;
191     MaybeStackArray<SpanInfo, 8> spanIndices;
192     int32_t spanIndicesCount = 0;
193 
194     bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
195     static bool isIntOrGroup(FormattedStringBuilder::Field field);
196     static bool isTrimmable(FormattedStringBuilder::Field field);
197     int32_t trimBack(int32_t limit) const;
198     int32_t trimFront(int32_t start) const;
199 };
200 
201 
202 // C API Helpers for FormattedValue
203 // Magic number as ASCII == "UFV"
204 struct UFormattedValueImpl;
205 typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
206 struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
207     // This pointer should be set by the child class.
208     FormattedValue* fFormattedValue = nullptr;
209 };
210 
211 
212 /** Boilerplate to check for valid status before dereferencing the fData pointer. */
213 #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
214     if (U_FAILURE(status)) { \
215         return returnExpression; \
216     } \
217     if (fData == nullptr) { \
218         status = fErrorCode; \
219         return returnExpression; \
220     } \
221 
222 
223 /** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
224 #define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
225     Name::Name(Name&& src) noexcept \
226             : fData(src.fData), fErrorCode(src.fErrorCode) { \
227         src.fData = nullptr; \
228         src.fErrorCode = U_INVALID_STATE_ERROR; \
229     } \
230     Name::~Name() { \
231         delete fData; \
232         fData = nullptr; \
233     } \
234     Name& Name::operator=(Name&& src) noexcept { \
235         delete fData; \
236         fData = src.fData; \
237         src.fData = nullptr; \
238         fErrorCode = src.fErrorCode; \
239         src.fErrorCode = U_INVALID_STATE_ERROR; \
240         return *this; \
241     } \
242     UnicodeString Name::toString(UErrorCode& status) const { \
243         UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
244         return fData->toString(status); \
245     } \
246     UnicodeString Name::toTempString(UErrorCode& status) const { \
247         UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
248         return fData->toTempString(status); \
249     } \
250     Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
251         UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
252         return fData->appendTo(appendable, status); \
253     } \
254     UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
255         UPRV_FORMATTED_VALUE_METHOD_GUARD(false) \
256         return fData->nextPosition(cfpos, status); \
257     }
258 
259 
260 /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
261 #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
262     U_CAPI CType* U_EXPORT2 \
263     Prefix ## _openResult (UErrorCode* ec) { \
264         if (U_FAILURE(*ec)) { \
265             return nullptr; \
266         } \
267         ImplType* impl = new ImplType(); \
268         if (impl == nullptr) { \
269             *ec = U_MEMORY_ALLOCATION_ERROR; \
270             return nullptr; \
271         } \
272         return static_cast<HelperType*>(impl)->exportForC(); \
273     } \
274     U_CAPI const UFormattedValue* U_EXPORT2 \
275     Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
276         const ImplType* result = HelperType::validate(uresult, *ec); \
277         if (U_FAILURE(*ec)) { return nullptr; } \
278         return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
279     } \
280     U_CAPI void U_EXPORT2 \
281     Prefix ## _closeResult (CType* uresult) { \
282         UErrorCode localStatus = U_ZERO_ERROR; \
283         const ImplType* impl = HelperType::validate(uresult, localStatus); \
284         delete impl; \
285     }
286 
287 
288 /**
289  * Implementation of the standard methods for a UFormattedValue "subclass" C API.
290  * @param CPPType The public C++ type, like FormattedList
291  * @param CType The public C type, like UFormattedList
292  * @param ImplType A name to use for the implementation class
293  * @param HelperType A name to use for the "mixin" typedef for C API conversion
294  * @param Prefix The C API prefix, like ulistfmt
295  * @param MagicNumber A unique 32-bit number to use to identify this type
296  */
297 #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
298     U_NAMESPACE_BEGIN \
299     class ImplType; \
300     typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
301     class ImplType : public UFormattedValueImpl, public HelperType { \
302     public: \
303         ImplType(); \
304         ~ImplType(); \
305         CPPType fImpl; \
306     }; \
307     ImplType::ImplType() { \
308         fFormattedValue = &fImpl; \
309     } \
310     ImplType::~ImplType() {} \
311     U_NAMESPACE_END \
312     UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
313 
314 
315 U_NAMESPACE_END
316 
317 #endif /* #if !UCONFIG_NO_FORMATTING */
318 #endif // __FORMVAL_IMPL_H__
319