| // © 2018 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| |
| #ifndef __FORMVAL_IMPL_H__ |
| #define __FORMVAL_IMPL_H__ |
| |
| #include "unicode/utypes.h" |
| #if !UCONFIG_NO_FORMATTING |
| |
| // This file contains compliant implementations of FormattedValue which can be |
| // leveraged by ICU formatters. |
| // |
| // Each implementation is defined in its own cpp file in order to split |
| // dependencies more modularly. |
| |
| #include "unicode/formattedvalue.h" |
| #include "capi_helper.h" |
| #include "fphdlimp.h" |
| #include "util.h" |
| #include "uvectr32.h" |
| #include "formatted_string_builder.h" |
| |
| |
| /** |
| * Represents the type of constraint for ConstrainedFieldPosition. |
| * |
| * Constraints are used to control the behavior of iteration in FormattedValue. |
| * |
| * @internal |
| */ |
| typedef enum UCFPosConstraintType { |
| /** |
| * Represents the lack of a constraint. |
| * |
| * This is the value of fConstraint if no "constrain" methods were called. |
| * |
| * @internal |
| */ |
| UCFPOS_CONSTRAINT_NONE = 0, |
| |
| /** |
| * Represents that the field category is constrained. |
| * |
| * This is the value of fConstraint if constraintCategory was called. |
| * |
| * FormattedValue implementations should not change the field category |
| * while this constraint is active. |
| * |
| * @internal |
| */ |
| UCFPOS_CONSTRAINT_CATEGORY, |
| |
| /** |
| * Represents that the field and field category are constrained. |
| * |
| * This is the value of fConstraint if constraintField was called. |
| * |
| * FormattedValue implementations should not change the field or field category |
| * while this constraint is active. |
| * |
| * @internal |
| */ |
| UCFPOS_CONSTRAINT_FIELD |
| } UCFPosConstraintType; |
| |
| |
| U_NAMESPACE_BEGIN |
| |
| |
| /** |
| * Implementation of FormattedValue using FieldPositionHandler to accept fields. |
| * |
| * TODO(ICU-20897): This class is unused. If it is not needed when fixing ICU-20897, |
| * it should be deleted. |
| */ |
| class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue { |
| public: |
| |
| /** @param initialFieldCapacity Initially allocate space for this many fields. */ |
| FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status); |
| |
| virtual ~FormattedValueFieldPositionIteratorImpl(); |
| |
| // Implementation of FormattedValue (const): |
| |
| UnicodeString toString(UErrorCode& status) const U_OVERRIDE; |
| UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; |
| Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; |
| UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; |
| |
| // Additional methods used during construction phase only (non-const): |
| |
| FieldPositionIteratorHandler getHandler(UErrorCode& status); |
| void appendString(UnicodeString string, UErrorCode& status); |
| |
| /** |
| * Computes the spans for duplicated values. |
| * For example, if the string has fields: |
| * |
| * ...aa..[b.cc]..d.[bb.e.c]..a.. |
| * |
| * then the spans will be the bracketed regions. |
| * |
| * Assumes that the currently known fields are sorted |
| * and all in the same category. |
| */ |
| void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status); |
| |
| /** |
| * Sorts the fields: start index first, length second. |
| */ |
| void sort(); |
| |
| private: |
| UnicodeString fString; |
| UVector32 fFields; |
| }; |
| |
| |
| // Internal struct that must be exported for MSVC |
| struct U_I18N_API SpanInfo { |
| int32_t spanValue; |
| int32_t length; |
| }; |
| |
| // Export an explicit template instantiation of the MaybeStackArray that |
| // is used as a data member of CEBuffer. |
| // |
| // When building DLLs for Windows this is required even though |
| // no direct access to the MaybeStackArray leaks out of the i18n library. |
| // |
| // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples. |
| // |
| #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN |
| template class U_I18N_API MaybeStackArray<SpanInfo, 8>; |
| #endif |
| |
| /** |
| * Implementation of FormattedValue based on FormattedStringBuilder. |
| * |
| * The implementation currently revolves around numbers and number fields. |
| * However, it can be generalized in the future when there is a need. |
| * |
| * @author sffc (Shane Carr) |
| */ |
| // Exported as U_I18N_API for tests |
| class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue { |
| public: |
| |
| FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField); |
| |
| virtual ~FormattedValueStringBuilderImpl(); |
| |
| // Implementation of FormattedValue (const): |
| |
| UnicodeString toString(UErrorCode& status) const U_OVERRIDE; |
| UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; |
| Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; |
| UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; |
| |
| // Additional helper functions: |
| UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const; |
| void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; |
| inline FormattedStringBuilder& getStringRef() { |
| return fString; |
| } |
| inline const FormattedStringBuilder& getStringRef() const { |
| return fString; |
| } |
| |
| /** |
| * Adds additional metadata used for span fields. |
| * |
| * spanValue: the index of the list item, for example. |
| * length: the length of the span, used to split adjacent fields. |
| */ |
| void appendSpanInfo(int32_t spanValue, int32_t length, UErrorCode& status); |
| void prependSpanInfo(int32_t spanValue, int32_t length, UErrorCode& status); |
| |
| private: |
| FormattedStringBuilder fString; |
| FormattedStringBuilder::Field fNumericField; |
| MaybeStackArray<SpanInfo, 8> spanIndices; |
| |
| bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const; |
| static bool isIntOrGroup(FormattedStringBuilder::Field field); |
| static bool isTrimmable(FormattedStringBuilder::Field field); |
| int32_t trimBack(int32_t limit) const; |
| int32_t trimFront(int32_t start) const; |
| }; |
| |
| |
| // C API Helpers for FormattedValue |
| // Magic number as ASCII == "UFV" |
| struct UFormattedValueImpl; |
| typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper; |
| struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper { |
| // This pointer should be set by the child class. |
| FormattedValue* fFormattedValue = nullptr; |
| }; |
| |
| |
| /** Boilerplate to check for valid status before dereferencing the fData pointer. */ |
| #define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \ |
| if (U_FAILURE(status)) { \ |
| return returnExpression; \ |
| } \ |
| if (fData == nullptr) { \ |
| status = fErrorCode; \ |
| return returnExpression; \ |
| } \ |
| |
| |
| /** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */ |
| #define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \ |
| Name::Name(Name&& src) U_NOEXCEPT \ |
| : fData(src.fData), fErrorCode(src.fErrorCode) { \ |
| src.fData = nullptr; \ |
| src.fErrorCode = U_INVALID_STATE_ERROR; \ |
| } \ |
| Name::~Name() { \ |
| delete fData; \ |
| fData = nullptr; \ |
| } \ |
| Name& Name::operator=(Name&& src) U_NOEXCEPT { \ |
| delete fData; \ |
| fData = src.fData; \ |
| src.fData = nullptr; \ |
| fErrorCode = src.fErrorCode; \ |
| src.fErrorCode = U_INVALID_STATE_ERROR; \ |
| return *this; \ |
| } \ |
| UnicodeString Name::toString(UErrorCode& status) const { \ |
| UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ |
| return fData->toString(status); \ |
| } \ |
| UnicodeString Name::toTempString(UErrorCode& status) const { \ |
| UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \ |
| return fData->toTempString(status); \ |
| } \ |
| Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \ |
| UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \ |
| return fData->appendTo(appendable, status); \ |
| } \ |
| UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \ |
| UPRV_FORMATTED_VALUE_METHOD_GUARD(false) \ |
| return fData->nextPosition(cfpos, status); \ |
| } |
| |
| |
| /** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */ |
| #define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \ |
| U_CAPI CType* U_EXPORT2 \ |
| Prefix ## _openResult (UErrorCode* ec) { \ |
| if (U_FAILURE(*ec)) { \ |
| return nullptr; \ |
| } \ |
| ImplType* impl = new ImplType(); \ |
| if (impl == nullptr) { \ |
| *ec = U_MEMORY_ALLOCATION_ERROR; \ |
| return nullptr; \ |
| } \ |
| return static_cast<HelperType*>(impl)->exportForC(); \ |
| } \ |
| U_CAPI const UFormattedValue* U_EXPORT2 \ |
| Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \ |
| const ImplType* result = HelperType::validate(uresult, *ec); \ |
| if (U_FAILURE(*ec)) { return nullptr; } \ |
| return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \ |
| } \ |
| U_CAPI void U_EXPORT2 \ |
| Prefix ## _closeResult (CType* uresult) { \ |
| UErrorCode localStatus = U_ZERO_ERROR; \ |
| const ImplType* impl = HelperType::validate(uresult, localStatus); \ |
| delete impl; \ |
| } |
| |
| |
| /** |
| * Implementation of the standard methods for a UFormattedValue "subclass" C API. |
| * @param CPPType The public C++ type, like FormattedList |
| * @param CType The public C type, like UFormattedList |
| * @param ImplType A name to use for the implementation class |
| * @param HelperType A name to use for the "mixin" typedef for C API conversion |
| * @param Prefix The C API prefix, like ulistfmt |
| * @param MagicNumber A unique 32-bit number to use to identify this type |
| */ |
| #define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \ |
| U_NAMESPACE_BEGIN \ |
| class ImplType; \ |
| typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \ |
| class ImplType : public UFormattedValueImpl, public HelperType { \ |
| public: \ |
| ImplType(); \ |
| ~ImplType(); \ |
| CPPType fImpl; \ |
| }; \ |
| ImplType::ImplType() { \ |
| fFormattedValue = &fImpl; \ |
| } \ |
| ImplType::~ImplType() {} \ |
| U_NAMESPACE_END \ |
| UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) |
| |
| |
| U_NAMESPACE_END |
| |
| #endif /* #if !UCONFIG_NO_FORMATTING */ |
| #endif // __FORMVAL_IMPL_H__ |