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 */
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.
72 */
73class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
74public:
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
111private:
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
126class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
127public:
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
150private:
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"
163struct UFormattedValueImpl;
164typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
165struct 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
274U_NAMESPACE_END
275
276#endif /* #if !UCONFIG_NO_FORMATTING */
277#endif // __FORMVAL_IMPL_H__
278