1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #ifndef __FORMVAL_IMPL_H__
5 #define __FORMVAL_IMPL_H__
7 #include "unicode/utypes.h"
8 #if !UCONFIG_NO_FORMATTING
10 // This file contains compliant implementations of FormattedValue which can be
11 // leveraged by ICU formatters.
13 // Each implementation is defined in its own cpp file in order to split
14 // dependencies more modularly.
16 #include "unicode/formattedvalue.h"
17 #include "capi_helper.h"
21 #include "formatted_string_builder.h"
25 * Represents the type of constraint for ConstrainedFieldPosition.
27 * Constraints are used to control the behavior of iteration in FormattedValue.
31 typedef enum UCFPosConstraintType
{
33 * Represents the lack of a constraint.
35 * This is the value of fConstraint if no "constrain" methods were called.
39 UCFPOS_CONSTRAINT_NONE
= 0,
42 * Represents that the field category is constrained.
44 * This is the value of fConstraint if constraintCategory was called.
46 * FormattedValue implementations should not change the field category
47 * while this constraint is active.
51 UCFPOS_CONSTRAINT_CATEGORY
,
54 * Represents that the field and field category are constrained.
56 * This is the value of fConstraint if constraintField was called.
58 * FormattedValue implementations should not change the field or field category
59 * while this constraint is active.
63 UCFPOS_CONSTRAINT_FIELD
64 } UCFPosConstraintType
;
71 * Implementation of FormattedValue using FieldPositionHandler to accept fields.
73 class FormattedValueFieldPositionIteratorImpl
: public UMemory
, public FormattedValue
{
76 /** @param initialFieldCapacity Initially allocate space for this many fields. */
77 FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity
, UErrorCode
& status
);
79 virtual ~FormattedValueFieldPositionIteratorImpl();
81 // Implementation of FormattedValue (const):
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
;
88 // Additional methods used during construction phase only (non-const):
90 FieldPositionIteratorHandler
getHandler(UErrorCode
& status
);
91 void appendString(UnicodeString string
, UErrorCode
& status
);
94 * Computes the spans for duplicated values.
95 * For example, if the string has fields:
97 * ...aa..[b.cc]..d.[bb.e.c]..a..
99 * then the spans will be the bracketed regions.
101 * Assumes that the currently known fields are sorted
102 * and all in the same category.
104 void addOverlapSpans(UFieldCategory spanCategory
, int8_t firstIndex
, UErrorCode
& status
);
107 * Sorts the fields: start index first, length second.
112 UnicodeString fString
;
118 * Implementation of FormattedValue based on FormattedStringBuilder.
120 * The implementation currently revolves around numbers and number fields.
121 * However, it can be generalized in the future when there is a need.
123 * @author sffc (Shane Carr)
125 // Exported as U_I18N_API for tests
126 class U_I18N_API FormattedValueStringBuilderImpl
: public UMemory
, public FormattedValue
{
129 FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField
);
131 virtual ~FormattedValueStringBuilderImpl();
133 // Implementation of FormattedValue (const):
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
;
140 // Additional helper functions:
141 UBool
nextFieldPosition(FieldPosition
& fp
, UErrorCode
& status
) const;
142 void getAllFieldPositions(FieldPositionIteratorHandler
& fpih
, UErrorCode
& status
) const;
143 inline FormattedStringBuilder
& getStringRef() {
146 inline const FormattedStringBuilder
& getStringRef() const {
151 FormattedStringBuilder fString
;
152 FormattedStringBuilder::Field fNumericField
;
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;
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;
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; \
177 if (fData == nullptr) { \
178 status = fErrorCode; \
179 return returnExpression; \
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; \
194 Name& Name::operator=(Name&& src) U_NOEXCEPT { \
197 src.fData = nullptr; \
198 fErrorCode = src.fErrorCode; \
199 src.fErrorCode = U_INVALID_STATE_ERROR; \
202 UnicodeString Name::toString(UErrorCode& status) const { \
203 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
204 return fData->toString(status); \
206 UnicodeString Name::toTempString(UErrorCode& status) const { \
207 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
208 return fData->toTempString(status); \
210 Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
211 UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
212 return fData->appendTo(appendable, status); \
214 UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
215 UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \
216 return fData->nextPosition(cfpos, status); \
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)) { \
227 ImplType* impl = new ImplType(); \
228 if (impl == nullptr) { \
229 *ec = U_MEMORY_ALLOCATION_ERROR; \
232 return static_cast<HelperType*>(impl)->exportForC(); \
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(); \
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); \
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
257 #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
260 typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
261 class ImplType : public UFormattedValueImpl, public HelperType { \
267 ImplType::ImplType() { \
268 fFormattedValue = &fImpl; \
270 ImplType::~ImplType() {} \
272 UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
277 #endif /* #if !UCONFIG_NO_FORMATTING */
278 #endif // __FORMVAL_IMPL_H__