formattedval_impl.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // © 2018 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. #ifndef __FORMVAL_IMPL_H__
  4. #define __FORMVAL_IMPL_H__
  5. #include "unicode/utypes.h"
  6. #if !UCONFIG_NO_FORMATTING
  7. // This file contains compliant implementations of FormattedValue which can be
  8. // leveraged by ICU formatters.
  9. //
  10. // Each implementation is defined in its own cpp file in order to split
  11. // dependencies more modularly.
  12. #include "unicode/formattedvalue.h"
  13. #include "capi_helper.h"
  14. #include "fphdlimp.h"
  15. #include "util.h"
  16. #include "uvectr32.h"
  17. #include "formatted_string_builder.h"
  18. /**
  19. * Represents the type of constraint for ConstrainedFieldPosition.
  20. *
  21. * Constraints are used to control the behavior of iteration in FormattedValue.
  22. *
  23. * @internal
  24. */
  25. typedef enum UCFPosConstraintType {
  26. /**
  27. * Represents the lack of a constraint.
  28. *
  29. * This is the value of fConstraint if no "constrain" methods were called.
  30. *
  31. * @internal
  32. */
  33. UCFPOS_CONSTRAINT_NONE = 0,
  34. /**
  35. * Represents that the field category is constrained.
  36. *
  37. * This is the value of fConstraint if constraintCategory was called.
  38. *
  39. * FormattedValue implementations should not change the field category
  40. * while this constraint is active.
  41. *
  42. * @internal
  43. */
  44. UCFPOS_CONSTRAINT_CATEGORY,
  45. /**
  46. * Represents that the field and field category are constrained.
  47. *
  48. * This is the value of fConstraint if constraintField was called.
  49. *
  50. * FormattedValue implementations should not change the field or field category
  51. * while this constraint is active.
  52. *
  53. * @internal
  54. */
  55. UCFPOS_CONSTRAINT_FIELD
  56. } UCFPosConstraintType;
  57. U_NAMESPACE_BEGIN
  58. /**
  59. * Implementation of FormattedValue using FieldPositionHandler to accept fields.
  60. *
  61. * TODO(ICU-20897): This class is unused. If it is not needed when fixing ICU-20897,
  62. * it should be deleted.
  63. */
  64. class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
  65. public:
  66. /** @param initialFieldCapacity Initially allocate space for this many fields. */
  67. FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status);
  68. virtual ~FormattedValueFieldPositionIteratorImpl();
  69. // Implementation of FormattedValue (const):
  70. UnicodeString toString(UErrorCode& status) const override;
  71. UnicodeString toTempString(UErrorCode& status) const override;
  72. Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override;
  73. UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override;
  74. // Additional methods used during construction phase only (non-const):
  75. FieldPositionIteratorHandler getHandler(UErrorCode& status);
  76. void appendString(UnicodeString string, UErrorCode& status);
  77. /**
  78. * Computes the spans for duplicated values.
  79. * For example, if the string has fields:
  80. *
  81. * ...aa..[b.cc]..d.[bb.e.c]..a..
  82. *
  83. * then the spans will be the bracketed regions.
  84. *
  85. * Assumes that the currently known fields are sorted
  86. * and all in the same category.
  87. */
  88. void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status);
  89. /**
  90. * Sorts the fields: start index first, length second.
  91. */
  92. void sort();
  93. private:
  94. UnicodeString fString;
  95. UVector32 fFields;
  96. };
  97. // Internal struct that must be exported for MSVC
  98. struct U_I18N_API SpanInfo {
  99. UFieldCategory category;
  100. int32_t spanValue;
  101. int32_t start;
  102. int32_t length;
  103. };
  104. // Export an explicit template instantiation of the MaybeStackArray that
  105. // is used as a data member of CEBuffer.
  106. //
  107. // When building DLLs for Windows this is required even though
  108. // no direct access to the MaybeStackArray leaks out of the i18n library.
  109. //
  110. // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
  111. //
  112. #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
  113. template class U_I18N_API MaybeStackArray<SpanInfo, 8>;
  114. #endif
  115. /**
  116. * Implementation of FormattedValue based on FormattedStringBuilder.
  117. *
  118. * The implementation currently revolves around numbers and number fields.
  119. * However, it can be generalized in the future when there is a need.
  120. *
  121. * @author sffc (Shane Carr)
  122. */
  123. // Exported as U_I18N_API for tests
  124. class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
  125. public:
  126. FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
  127. virtual ~FormattedValueStringBuilderImpl();
  128. FormattedValueStringBuilderImpl(FormattedValueStringBuilderImpl&&) = default;
  129. FormattedValueStringBuilderImpl& operator=(FormattedValueStringBuilderImpl&&) = default;
  130. // Implementation of FormattedValue (const):
  131. UnicodeString toString(UErrorCode& status) const override;
  132. UnicodeString toTempString(UErrorCode& status) const override;
  133. Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override;
  134. UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override;
  135. // Additional helper functions:
  136. UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
  137. void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
  138. inline FormattedStringBuilder& getStringRef() {
  139. return fString;
  140. }
  141. inline const FormattedStringBuilder& getStringRef() const {
  142. return fString;
  143. }
  144. void resetString();
  145. /**
  146. * Adds additional metadata used for span fields.
  147. *
  148. * category: the category to use for the span field.
  149. * spanValue: the value of the span field: index of the list item, for example.
  150. * start: the start position within the string of the span. -1 if unknown.
  151. * length: the length of the span, used to split adjacent fields.
  152. */
  153. void appendSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
  154. void prependSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status);
  155. private:
  156. FormattedStringBuilder fString;
  157. FormattedStringBuilder::Field fNumericField;
  158. MaybeStackArray<SpanInfo, 8> spanIndices;
  159. int32_t spanIndicesCount = 0;
  160. bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
  161. static bool isIntOrGroup(FormattedStringBuilder::Field field);
  162. static bool isTrimmable(FormattedStringBuilder::Field field);
  163. int32_t trimBack(int32_t limit) const;
  164. int32_t trimFront(int32_t start) const;
  165. };
  166. // C API Helpers for FormattedValue
  167. // Magic number as ASCII == "UFV"
  168. struct UFormattedValueImpl;
  169. typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
  170. struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
  171. // This pointer should be set by the child class.
  172. FormattedValue* fFormattedValue = nullptr;
  173. };
  174. /** Boilerplate to check for valid status before dereferencing the fData pointer. */
  175. #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
  176. if (U_FAILURE(status)) { \
  177. return returnExpression; \
  178. } \
  179. if (fData == nullptr) { \
  180. status = fErrorCode; \
  181. return returnExpression; \
  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) 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) 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. /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
  219. #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
  220. U_CAPI CType* U_EXPORT2 \
  221. Prefix ## _openResult (UErrorCode* ec) { \
  222. if (U_FAILURE(*ec)) { \
  223. return nullptr; \
  224. } \
  225. ImplType* impl = new ImplType(); \
  226. if (impl == nullptr) { \
  227. *ec = U_MEMORY_ALLOCATION_ERROR; \
  228. return nullptr; \
  229. } \
  230. return static_cast<HelperType*>(impl)->exportForC(); \
  231. } \
  232. U_CAPI const UFormattedValue* U_EXPORT2 \
  233. Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
  234. const ImplType* result = HelperType::validate(uresult, *ec); \
  235. if (U_FAILURE(*ec)) { return nullptr; } \
  236. return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
  237. } \
  238. U_CAPI void U_EXPORT2 \
  239. Prefix ## _closeResult (CType* uresult) { \
  240. UErrorCode localStatus = U_ZERO_ERROR; \
  241. const ImplType* impl = HelperType::validate(uresult, localStatus); \
  242. delete impl; \
  243. }
  244. /**
  245. * Implementation of the standard methods for a UFormattedValue "subclass" C API.
  246. * @param CPPType The public C++ type, like FormattedList
  247. * @param CType The public C type, like UFormattedList
  248. * @param ImplType A name to use for the implementation class
  249. * @param HelperType A name to use for the "mixin" typedef for C API conversion
  250. * @param Prefix The C API prefix, like ulistfmt
  251. * @param MagicNumber A unique 32-bit number to use to identify this type
  252. */
  253. #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
  254. U_NAMESPACE_BEGIN \
  255. class ImplType; \
  256. typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
  257. class ImplType : public UFormattedValueImpl, public HelperType { \
  258. public: \
  259. ImplType(); \
  260. ~ImplType(); \
  261. CPPType fImpl; \
  262. }; \
  263. ImplType::ImplType() { \
  264. fFormattedValue = &fImpl; \
  265. } \
  266. ImplType::~ImplType() {} \
  267. U_NAMESPACE_END \
  268. UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
  269. U_NAMESPACE_END
  270. #endif /* #if !UCONFIG_NO_FORMATTING */
  271. #endif // __FORMVAL_IMPL_H__