• 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 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;
getStringRef()143     inline FormattedStringBuilder& getStringRef() {
144         return fString;
145     }
getStringRef()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     int32_t trimBack(int32_t limit) const;
157     int32_t trimFront(int32_t start) const;
158 };
159 
160 
161 // C API Helpers for FormattedValue
162 // Magic number as ASCII == "UFV"
163 struct UFormattedValueImpl;
164 typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
165 struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
166     // This pointer should be set by the child class.
167     FormattedValue* fFormattedValue = nullptr;
168 };
169 
170 
171 /** Boilerplate to check for valid status before dereferencing the fData pointer. */
172 #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
173     if (U_FAILURE(status)) { \
174         return returnExpression; \
175     } \
176     if (fData == nullptr) { \
177         status = fErrorCode; \
178         return returnExpression; \
179     } \
180 
181 
182 /** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
183 #define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
184     Name::Name(Name&& src) U_NOEXCEPT \
185             : fData(src.fData), fErrorCode(src.fErrorCode) { \
186         src.fData = nullptr; \
187         src.fErrorCode = U_INVALID_STATE_ERROR; \
188     } \
189     Name::~Name() { \
190         delete fData; \
191         fData = nullptr; \
192     } \
193     Name& Name::operator=(Name&& src) U_NOEXCEPT { \
194         delete fData; \
195         fData = src.fData; \
196         src.fData = nullptr; \
197         fErrorCode = src.fErrorCode; \
198         src.fErrorCode = U_INVALID_STATE_ERROR; \
199         return *this; \
200     } \
201     UnicodeString Name::toString(UErrorCode& status) const { \
202         UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
203         return fData->toString(status); \
204     } \
205     UnicodeString Name::toTempString(UErrorCode& status) const { \
206         UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
207         return fData->toTempString(status); \
208     } \
209     Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
210         UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
211         return fData->appendTo(appendable, status); \
212     } \
213     UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
214         UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \
215         return fData->nextPosition(cfpos, status); \
216     }
217 
218 
219 /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
220 #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
221     U_CAPI CType* U_EXPORT2 \
222     Prefix ## _openResult (UErrorCode* ec) { \
223         if (U_FAILURE(*ec)) { \
224             return nullptr; \
225         } \
226         ImplType* impl = new ImplType(); \
227         if (impl == nullptr) { \
228             *ec = U_MEMORY_ALLOCATION_ERROR; \
229             return nullptr; \
230         } \
231         return static_cast<HelperType*>(impl)->exportForC(); \
232     } \
233     U_DRAFT const UFormattedValue* U_EXPORT2 \
234     Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
235         const ImplType* result = HelperType::validate(uresult, *ec); \
236         if (U_FAILURE(*ec)) { return nullptr; } \
237         return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
238     } \
239     U_CAPI void U_EXPORT2 \
240     Prefix ## _closeResult (CType* uresult) { \
241         UErrorCode localStatus = U_ZERO_ERROR; \
242         const ImplType* impl = HelperType::validate(uresult, localStatus); \
243         delete impl; \
244     }
245 
246 
247 /**
248  * Implementation of the standard methods for a UFormattedValue "subclass" C API.
249  * @param CPPType The public C++ type, like FormattedList
250  * @param CType The public C type, like UFormattedList
251  * @param ImplType A name to use for the implementation class
252  * @param HelperType A name to use for the "mixin" typedef for C API conversion
253  * @param Prefix The C API prefix, like ulistfmt
254  * @param MagicNumber A unique 32-bit number to use to identify this type
255  */
256 #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
257     U_NAMESPACE_BEGIN \
258     class ImplType; \
259     typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
260     class ImplType : public UFormattedValueImpl, public HelperType { \
261     public: \
262         ImplType(); \
263         ~ImplType(); \
264         CPPType fImpl; \
265     }; \
266     ImplType::ImplType() { \
267         fFormattedValue = &fImpl; \
268     } \
269     ImplType::~ImplType() {} \
270     U_NAMESPACE_END \
271     UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
272 
273 
274 U_NAMESPACE_END
275 
276 #endif /* #if !UCONFIG_NO_FORMATTING */
277 #endif // __FORMVAL_IMPL_H__
278