blob: c0dec83ba1eb369aa45b03e2c31c3ac7227edec2 [file] [log] [blame]
Victor Chang73229502020-09-17 13:39:19 +01001// © 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 */
31typedef 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
67U_NAMESPACE_BEGIN
68
69
70/**
71 * Implementation of FormattedValue using FieldPositionHandler to accept fields.
Victor Changce4bf3c2021-01-19 16:34:24 +000072 *
73 * TODO(ICU-20897): This class is unused. If it is not needed when fixing ICU-20897,
74 * it should be deleted.
Victor Chang73229502020-09-17 13:39:19 +010075 */
76class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
77public:
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 U_OVERRIDE;
87 UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
88 Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
89 UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_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
114private:
115 UnicodeString fString;
116 UVector32 fFields;
117};
118
119
Victor Changce4bf3c2021-01-19 16:34:24 +0000120// Internal struct that must be exported for MSVC
121struct U_I18N_API SpanInfo {
122 int32_t spanValue;
123 int32_t length;
124};
125
126// Export an explicit template instantiation of the MaybeStackArray that
127// is used as a data member of CEBuffer.
128//
129// When building DLLs for Windows this is required even though
130// no direct access to the MaybeStackArray leaks out of the i18n library.
131//
132// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
133//
134#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
135template class U_I18N_API MaybeStackArray<SpanInfo, 8>;
136#endif
137
Victor Chang73229502020-09-17 13:39:19 +0100138/**
139 * Implementation of FormattedValue based on FormattedStringBuilder.
140 *
141 * The implementation currently revolves around numbers and number fields.
142 * However, it can be generalized in the future when there is a need.
143 *
144 * @author sffc (Shane Carr)
145 */
146// Exported as U_I18N_API for tests
147class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
148public:
149
150 FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
151
152 virtual ~FormattedValueStringBuilderImpl();
153
154 // Implementation of FormattedValue (const):
155
156 UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
157 UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
158 Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
159 UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
160
161 // Additional helper functions:
162 UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
163 void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
164 inline FormattedStringBuilder& getStringRef() {
165 return fString;
166 }
167 inline const FormattedStringBuilder& getStringRef() const {
168 return fString;
169 }
170
Victor Changce4bf3c2021-01-19 16:34:24 +0000171 /**
172 * Adds additional metadata used for span fields.
173 *
174 * spanValue: the index of the list item, for example.
175 * length: the length of the span, used to split adjacent fields.
176 */
177 void appendSpanInfo(int32_t spanValue, int32_t length, UErrorCode& status);
178 void prependSpanInfo(int32_t spanValue, int32_t length, UErrorCode& status);
179
Victor Chang73229502020-09-17 13:39:19 +0100180private:
181 FormattedStringBuilder fString;
182 FormattedStringBuilder::Field fNumericField;
Victor Changce4bf3c2021-01-19 16:34:24 +0000183 MaybeStackArray<SpanInfo, 8> spanIndices;
Victor Chang73229502020-09-17 13:39:19 +0100184
185 bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
186 static bool isIntOrGroup(FormattedStringBuilder::Field field);
Victor Changce4bf3c2021-01-19 16:34:24 +0000187 static bool isTrimmable(FormattedStringBuilder::Field field);
Victor Chang73229502020-09-17 13:39:19 +0100188 int32_t trimBack(int32_t limit) const;
189 int32_t trimFront(int32_t start) const;
190};
191
192
193// C API Helpers for FormattedValue
194// Magic number as ASCII == "UFV"
195struct UFormattedValueImpl;
196typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
197struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
198 // This pointer should be set by the child class.
199 FormattedValue* fFormattedValue = nullptr;
200};
201
202
203/** Boilerplate to check for valid status before dereferencing the fData pointer. */
204#define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
205 if (U_FAILURE(status)) { \
206 return returnExpression; \
207 } \
208 if (fData == nullptr) { \
209 status = fErrorCode; \
210 return returnExpression; \
211 } \
212
213
214/** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
215#define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
216 Name::Name(Name&& src) U_NOEXCEPT \
217 : fData(src.fData), fErrorCode(src.fErrorCode) { \
218 src.fData = nullptr; \
219 src.fErrorCode = U_INVALID_STATE_ERROR; \
220 } \
221 Name::~Name() { \
222 delete fData; \
223 fData = nullptr; \
224 } \
225 Name& Name::operator=(Name&& src) U_NOEXCEPT { \
226 delete fData; \
227 fData = src.fData; \
228 src.fData = nullptr; \
229 fErrorCode = src.fErrorCode; \
230 src.fErrorCode = U_INVALID_STATE_ERROR; \
231 return *this; \
232 } \
233 UnicodeString Name::toString(UErrorCode& status) const { \
234 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
235 return fData->toString(status); \
236 } \
237 UnicodeString Name::toTempString(UErrorCode& status) const { \
238 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
239 return fData->toTempString(status); \
240 } \
241 Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
242 UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
243 return fData->appendTo(appendable, status); \
244 } \
245 UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
Victor Changce4bf3c2021-01-19 16:34:24 +0000246 UPRV_FORMATTED_VALUE_METHOD_GUARD(false) \
Victor Chang73229502020-09-17 13:39:19 +0100247 return fData->nextPosition(cfpos, status); \
248 }
249
250
251/** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
252#define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
253 U_CAPI CType* U_EXPORT2 \
254 Prefix ## _openResult (UErrorCode* ec) { \
255 if (U_FAILURE(*ec)) { \
256 return nullptr; \
257 } \
258 ImplType* impl = new ImplType(); \
259 if (impl == nullptr) { \
260 *ec = U_MEMORY_ALLOCATION_ERROR; \
261 return nullptr; \
262 } \
263 return static_cast<HelperType*>(impl)->exportForC(); \
264 } \
Victor Changce4bf3c2021-01-19 16:34:24 +0000265 U_CAPI const UFormattedValue* U_EXPORT2 \
Victor Chang73229502020-09-17 13:39:19 +0100266 Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
267 const ImplType* result = HelperType::validate(uresult, *ec); \
268 if (U_FAILURE(*ec)) { return nullptr; } \
269 return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
270 } \
271 U_CAPI void U_EXPORT2 \
272 Prefix ## _closeResult (CType* uresult) { \
273 UErrorCode localStatus = U_ZERO_ERROR; \
274 const ImplType* impl = HelperType::validate(uresult, localStatus); \
275 delete impl; \
276 }
277
278
279/**
280 * Implementation of the standard methods for a UFormattedValue "subclass" C API.
281 * @param CPPType The public C++ type, like FormattedList
282 * @param CType The public C type, like UFormattedList
283 * @param ImplType A name to use for the implementation class
284 * @param HelperType A name to use for the "mixin" typedef for C API conversion
285 * @param Prefix The C API prefix, like ulistfmt
286 * @param MagicNumber A unique 32-bit number to use to identify this type
287 */
288#define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
289 U_NAMESPACE_BEGIN \
290 class ImplType; \
291 typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
292 class ImplType : public UFormattedValueImpl, public HelperType { \
293 public: \
294 ImplType(); \
295 ~ImplType(); \
296 CPPType fImpl; \
297 }; \
298 ImplType::ImplType() { \
299 fFormattedValue = &fImpl; \
300 } \
301 ImplType::~ImplType() {} \
302 U_NAMESPACE_END \
303 UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
304
305
306U_NAMESPACE_END
307
308#endif /* #if !UCONFIG_NO_FORMATTING */
309#endif // __FORMVAL_IMPL_H__