// © 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 "number_stringbuilder.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 using FieldPositionHandler to accept fields. */ 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; }; class FormattedValueNumberStringBuilderImpl : public UMemory, public FormattedValue { public: FormattedValueNumberStringBuilderImpl(number::impl::Field numericField); virtual ~FormattedValueNumberStringBuilderImpl(); // 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; inline number::impl::NumberStringBuilder& getStringRef() { return fString; } inline const number::impl::NumberStringBuilder& getStringRef() const { return fString; } private: number::impl::NumberStringBuilder fString; number::impl::Field fNumericField; }; // C API Helpers for FormattedValue // Magic number as ASCII == "UFV" struct UFormattedValueImpl; typedef IcuCApiHelper 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(impl)->exportForC(); \ } \ U_DRAFT 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(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 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__