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