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 static bool isNumericField(FormattedStringBuilder::Field field); 157 int32_t trimBack(int32_t limit) const; 158 int32_t trimFront(int32_t start) const; 159 }; 160 161 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; 169 }; 170 171 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; \ 176 } \ 177 if (fData == nullptr) { \ 178 status = fErrorCode; \ 179 return returnExpression; \ 180 } \ 181 182 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; \ 189 } \ 190 Name::~Name() { \ 191 delete fData; \ 192 fData = nullptr; \ 193 } \ 194 Name& Name::operator=(Name&& src) U_NOEXCEPT { \ 195 delete fData; \ 196 fData = src.fData; \ 197 src.fData = nullptr; \ 198 fErrorCode = src.fErrorCode; \ 199 src.fErrorCode = U_INVALID_STATE_ERROR; \ 200 return *this; \ 201 } \ 202 UnicodeString Name::toString(UErrorCode& status) const { \ 203 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ 204 return fData->toString(status); \ 205 } \ 206 UnicodeString Name::toTempString(UErrorCode& status) const { \ 207 UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ 208 return fData->toTempString(status); \ 209 } \ 210 Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \ 211 UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \ 212 return fData->appendTo(appendable, status); \ 213 } \ 214 UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \ 215 UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \ 216 return fData->nextPosition(cfpos, status); \ 217 } 218 219 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)) { \ 225 return nullptr; \ 226 } \ 227 ImplType* impl = new ImplType(); \ 228 if (impl == nullptr) { \ 229 *ec = U_MEMORY_ALLOCATION_ERROR; \ 230 return nullptr; \ 231 } \ 232 return static_cast<HelperType*>(impl)->exportForC(); \ 233 } \ 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(); \ 239 } \ 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); \ 244 delete impl; \ 245 } 246 247 248 /** 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 256 */ 257 #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \ 258 U_NAMESPACE_BEGIN \ 259 class ImplType; \ 260 typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \ 261 class ImplType : public UFormattedValueImpl, public HelperType { \ 262 public: \ 263 ImplType(); \ 264 ~ImplType(); \ 265 CPPType fImpl; \ 266 }; \ 267 ImplType::ImplType() { \ 268 fFormattedValue = &fImpl; \ 269 } \ 270 ImplType::~ImplType() {} \ 271 U_NAMESPACE_END \ 272 UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) 273 274 275 U_NAMESPACE_END 276 277 #endif /* #if !UCONFIG_NO_FORMATTING */ 278 #endif // __FORMVAL_IMPL_H__ 279