diff --git a/icu4c/source/i18n/messageformat2.cpp b/icu4c/source/i18n/messageformat2.cpp index 9843c9920e7d..067291a80c36 100644 --- a/icu4c/source/i18n/messageformat2.cpp +++ b/icu4c/source/i18n/messageformat2.cpp @@ -173,13 +173,14 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, } // Look up the function name - Function* function = lookupFunction(functionName, status); + FunctionFactory* functionFactory = lookupFunctionFactory(functionName, status); if (U_FAILURE(status)) { // Function is unknown -- set error and use the fallback value status = U_ZERO_ERROR; context.getErrors().setUnknownFunction(functionName, status); return InternalValue::fallback(fallbackStr); } + LocalPointer function(functionFactory->createFunction(locale, status)); // Value is not a fallback, so we can safely call takeValue() LocalPointer functionArg(rand.takeValue(status)); U_ASSERT(U_SUCCESS(status)); diff --git a/icu4c/source/i18n/messageformat2_formatter.cpp b/icu4c/source/i18n/messageformat2_formatter.cpp index cf808fa26654..e73a8ec827f0 100644 --- a/icu4c/source/i18n/messageformat2_formatter.cpp +++ b/icu4c/source/i18n/messageformat2_formatter.cpp @@ -122,18 +122,23 @@ namespace message2 { // Set up the standard function registry MFFunctionRegistry::Builder standardFunctionsBuilder(success); - Function* dateTime = StandardFunctions::DateTime::dateTime(locale, success); - Function* date = StandardFunctions::DateTime::date(locale, success); - Function* time = StandardFunctions::DateTime::time(locale, success); - standardFunctionsBuilder.adoptFunction(FunctionName(UnicodeString("datetime")), dateTime, success) - .adoptFunction(FunctionName(UnicodeString("date")), date, success) - .adoptFunction(FunctionName(UnicodeString("time")), time, success) - .adoptFunction(FunctionName(UnicodeString("number")), - StandardFunctions::Number::number(locale, success), success) - .adoptFunction(FunctionName(UnicodeString("integer")), - StandardFunctions::Number::integer(locale, success), success) - .adoptFunction(FunctionName(UnicodeString("string")), - StandardFunctions::String::string(locale, success), success); + LocalPointer dateTime(StandardFunctions::DateTimeFactory::dateTime(success)); + LocalPointer date(StandardFunctions::DateTimeFactory::date(success)); + LocalPointer time(StandardFunctions::DateTimeFactory::time(success)); + LocalPointer number(StandardFunctions::NumberFactory::number(success)); + LocalPointer integer(StandardFunctions::NumberFactory::integer(success)); + LocalPointer string(StandardFunctions::StringFactory::string(success)); + CHECK_ERROR(success); + standardFunctionsBuilder.adoptFunctionFactory(FunctionName(UnicodeString("datetime")), + dateTime.orphan(), success) + .adoptFunctionFactory(FunctionName(UnicodeString("date")), date.orphan(), success) + .adoptFunctionFactory(FunctionName(UnicodeString("time")), time.orphan(), success) + .adoptFunctionFactory(FunctionName(UnicodeString("number")), + number.orphan(), success) + .adoptFunctionFactory(FunctionName(UnicodeString("integer")), + integer.orphan(), success) + .adoptFunctionFactory(FunctionName(UnicodeString("string")), + string.orphan(), success); CHECK_ERROR(success); standardMFFunctionRegistry = standardFunctionsBuilder.build(); CHECK_ERROR(success); @@ -220,8 +225,9 @@ namespace message2 { return standardMFFunctionRegistry.hasFunction(functionName); } - Function* MessageFormatter::lookupFunction(const FunctionName& functionName, - UErrorCode& status) const { + FunctionFactory* + MessageFormatter::lookupFunctionFactory(const FunctionName& functionName, + UErrorCode& status) const { NULL_ON_ERROR(status); if (isBuiltInFunction(functionName)) { @@ -229,7 +235,7 @@ namespace message2 { } if (hasCustomMFFunctionRegistry()) { const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry(); - Function* function = customMFFunctionRegistry.getFunction(functionName); + FunctionFactory* function = customMFFunctionRegistry.getFunction(functionName); if (function != nullptr) { return function; } diff --git a/icu4c/source/i18n/messageformat2_function_registry.cpp b/icu4c/source/i18n/messageformat2_function_registry.cpp index 31defd097782..da6622b2d073 100644 --- a/icu4c/source/i18n/messageformat2_function_registry.cpp +++ b/icu4c/source/i18n/messageformat2_function_registry.cpp @@ -38,6 +38,7 @@ namespace message2 { // Function registry implementation +FunctionFactory::~FunctionFactory() {} Function::~Function() {} FunctionValue::~FunctionValue() {} @@ -50,9 +51,10 @@ MFFunctionRegistry MFFunctionRegistry::Builder::build() { return result; } -MFFunctionRegistry::Builder& MFFunctionRegistry::Builder::adoptFunction(const FunctionName& functionName, - Function* function, - UErrorCode& errorCode) { +MFFunctionRegistry::Builder& +MFFunctionRegistry::Builder::adoptFunctionFactory(const FunctionName& functionName, + FunctionFactory* function, + UErrorCode& errorCode) { if (U_SUCCESS(errorCode)) { U_ASSERT(functions != nullptr); functions->put(functionName, function, errorCode); @@ -98,9 +100,9 @@ MFFunctionRegistry::Builder::~Builder() { // Returns non-owned pointer. Returns pointer rather than reference because it can fail. // Returns non-const because Function is mutable. -Function* MFFunctionRegistry::getFunction(const FunctionName& functionName) const { +FunctionFactory* MFFunctionRegistry::getFunction(const FunctionName& functionName) const { U_ASSERT(functions != nullptr); - return static_cast(functions->get(functionName)); + return static_cast(functions->get(functionName)); } UBool MFFunctionRegistry::getDefaultFormatterNameByType(const UnicodeString& type, FunctionName& name) const { @@ -225,6 +227,40 @@ MFFunctionRegistry::~MFFunctionRegistry() { // --------- Number +/* static */ StandardFunctions::NumberFactory* +StandardFunctions::NumberFactory::integer(UErrorCode& success) { + return NumberFactory::create(true, success); +} + +/* static */ StandardFunctions::NumberFactory* +StandardFunctions::NumberFactory::number(UErrorCode& success) { + return NumberFactory::create(false, success); +} + +/* static */ StandardFunctions::NumberFactory* +StandardFunctions::NumberFactory::create(bool isInteger, + UErrorCode& success) { + NULL_ON_ERROR(success); + + LocalPointer result(new NumberFactory(isInteger)); + if (!result.isValid()) { + success = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return result.orphan(); +} + +Function* +StandardFunctions::NumberFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + Number* result = new Number(locale, isInteger); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + /* static */ StandardFunctions::Number* StandardFunctions::Number::integer(const Locale& loc, UErrorCode& success) { return create(loc, true, success); @@ -582,6 +618,7 @@ UnicodeString StandardFunctions::NumberValue::formatToString(UErrorCode& errorCo return formattedNumber.toString(errorCode); } +StandardFunctions::NumberFactory::~NumberFactory() {} StandardFunctions::Number::~Number() {} StandardFunctions::NumberValue::~NumberValue() {} @@ -699,23 +736,49 @@ static UnicodeString defaultForOption(const UnicodeString& optionName) { } */ -/* static */ StandardFunctions::DateTime* -StandardFunctions::DateTime::date(const Locale& loc, UErrorCode& success) { - return DateTime::create(loc, DateTimeType::kDate, success); +/* static */ StandardFunctions::DateTimeFactory* +StandardFunctions::DateTimeFactory::date(UErrorCode& success) { + return DateTimeFactory::create(DateTimeType::kDate, success); } -/* static */ StandardFunctions::DateTime* -StandardFunctions::DateTime::time(const Locale& loc, UErrorCode& success) { - return DateTime::create(loc, DateTimeType::kTime, success); +/* static */ StandardFunctions::DateTimeFactory* +StandardFunctions::DateTimeFactory::time(UErrorCode& success) { + return DateTimeFactory::create(DateTimeType::kTime, success); } -/* static */ StandardFunctions::DateTime* -StandardFunctions::DateTime::dateTime(const Locale& loc, UErrorCode& success) { - return DateTime::create(loc, DateTimeType::kDateTime, success); +/* static */ StandardFunctions::DateTimeFactory* +StandardFunctions::DateTimeFactory::dateTime(UErrorCode& success) { + return DateTimeFactory::create(DateTimeType::kDateTime, success); +} + +/* static */ StandardFunctions::DateTimeFactory* +StandardFunctions::DateTimeFactory::create(DateTimeFactory::DateTimeType type, + UErrorCode& success) { + NULL_ON_ERROR(success); + + LocalPointer result(new DateTimeFactory(type)); + if (!result.isValid()) { + success = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return result.orphan(); +} + +Function* +StandardFunctions::DateTimeFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + DateTime* result = new DateTime(locale, type); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; } /* static */ StandardFunctions::DateTime* -StandardFunctions::DateTime::create(const Locale& loc, DateTimeType type, UErrorCode& success) { +StandardFunctions::DateTime::create(const Locale& loc, + DateTimeFactory::DateTimeType type, + UErrorCode& success) { NULL_ON_ERROR(success); LocalPointer result(new DateTime(loc, type)); @@ -728,7 +791,12 @@ StandardFunctions::DateTime::create(const Locale& loc, DateTimeType type, UError FunctionValue* StandardFunctions::DateTime::call(FunctionValue& val, FunctionOptions&& opts, UErrorCode& errorCode) { - auto result = new DateTimeValue(type, locale, val, std::move(opts), errorCode); + NULL_ON_ERROR(errorCode); + + auto result = new DateTimeValue(locale, type, val, std::move(opts), errorCode); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } return result; } @@ -761,8 +829,8 @@ UnicodeString StandardFunctions::DateTimeValue::formatToString(UErrorCode& statu return formattedDate; } -StandardFunctions::DateTimeValue::DateTimeValue(DateTime::DateTimeType type, - const Locale& locale, +StandardFunctions::DateTimeValue::DateTimeValue(const Locale& locale, + DateTimeFactory::DateTimeType type, FunctionValue& val, FunctionOptions&& options, UErrorCode& errorCode) { @@ -795,21 +863,23 @@ StandardFunctions::DateTimeValue::DateTimeValue(DateTime::DateTimeType type, bool hasTimeStyleOption = dateStyleOption.length() > 0; bool noOptions = opts.optionsCount() == 0; - bool useStyle = (type == DateTime::DateTimeType::kDateTime + using DateTimeType = DateTimeFactory::DateTimeType; + + bool useStyle = (type == DateTimeType::kDateTime && (hasDateStyleOption || hasTimeStyleOption || noOptions)) - || (type != DateTime::DateTimeType::kDateTime); + || (type != DateTimeType::kDateTime); - bool useDate = type == DateTime::DateTimeType::kDate - || (type == DateTime::DateTimeType::kDateTime + bool useDate = type == DateTimeType::kDate + || (type == DateTimeType::kDateTime && hasDateStyleOption); - bool useTime = type == DateTime::DateTimeType::kTime - || (type == DateTime::DateTimeType::kDateTime + bool useTime = type == DateTimeType::kTime + || (type == DateTimeType::kDateTime && hasTimeStyleOption); if (useStyle) { // Extract style options - if (type == DateTime::DateTimeType::kDateTime) { + if (type == DateTimeType::kDateTime) { // Note that the options-getting has to be repeated across the three cases, // since `:datetime` uses "dateStyle"/"timeStyle" and `:date` and `:time` // use "style" @@ -823,7 +893,7 @@ StandardFunctions::DateTimeValue::DateTimeValue(DateTime::DateTimeType type, } else { df.adoptInstead(DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale)); } - } else if (type == DateTime::DateTimeType::kDate) { + } else if (type == DateTimeType::kDate) { dateStyle = stringToStyle(opts.getStringFunctionOption(styleName), errorCode); df.adoptInstead(DateFormat::createDateInstance(dateStyle, locale)); } else { @@ -1010,11 +1080,24 @@ StandardFunctions::DateTimeValue::DateTimeValue(DateTime::DateTimeType type, formattedDate = result; } +StandardFunctions::DateTimeFactory::~DateTimeFactory() {} StandardFunctions::DateTime::~DateTime() {} StandardFunctions::DateTimeValue::~DateTimeValue() {} // --------- String +/* static */ StandardFunctions::StringFactory* +StandardFunctions::StringFactory::string(UErrorCode& success) { + NULL_ON_ERROR(success); + + LocalPointer result(new StringFactory()); + if (!result.isValid()) { + success = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return result.orphan(); +} + /* static */ StandardFunctions::String* StandardFunctions::String::string(const Locale& loc, UErrorCode& success) { NULL_ON_ERROR(success); @@ -1027,6 +1110,17 @@ StandardFunctions::String::string(const Locale& loc, UErrorCode& success) { return result.orphan(); } +Function* +StandardFunctions::StringFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + String* result = new String(locale); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + extern UnicodeString formattableToString(const Locale&, const Formattable&, UErrorCode&); FunctionValue* @@ -1075,6 +1169,7 @@ void StandardFunctions::StringValue::selectKeys(const UnicodeString* keys, } } +StandardFunctions::StringFactory::~StringFactory() {} StandardFunctions::String::~String() {} StandardFunctions::StringValue::~StringValue() {} diff --git a/icu4c/source/i18n/messageformat2_function_registry_internal.h b/icu4c/source/i18n/messageformat2_function_registry_internal.h index 32b0f2f55a42..bd46103cc85d 100644 --- a/icu4c/source/i18n/messageformat2_function_registry_internal.h +++ b/icu4c/source/i18n/messageformat2_function_registry_internal.h @@ -34,17 +34,15 @@ namespace message2 { class DateTime; class DateTimeValue; - class DateTime : public Function { + class DateTimeFactory : public FunctionFactory { public: - FunctionValue* call(FunctionValue& operand, - FunctionOptions&& options, - UErrorCode& errorCode) override; - static DateTime* date(const Locale&, UErrorCode&); - static DateTime* time(const Locale&, UErrorCode&); - static DateTime* dateTime(const Locale&, UErrorCode&); - virtual ~DateTime(); - + Function* createFunction(const Locale& locale, UErrorCode& status) override; + static DateTimeFactory* date(UErrorCode&); + static DateTimeFactory* time(UErrorCode&); + static DateTimeFactory* dateTime(UErrorCode&); + virtual ~DateTimeFactory(); private: + friend class DateTime; friend class DateTimeValue; typedef enum DateTimeType { @@ -53,15 +51,49 @@ namespace message2 { kDateTime } DateTimeType; + DateTimeType type; + + static DateTimeFactory* create(const DateTimeType, + UErrorCode&); + + DateTimeFactory(const DateTimeType t) : type(t) {} + }; // class DateTimeFactory + + class DateTime : public Function { + public: + FunctionValue* call(FunctionValue& operand, + FunctionOptions&& options, + UErrorCode& errorCode) override; + virtual ~DateTime(); + + private: + friend class DateTimeFactory; + friend class DateTimeValue; + Locale locale; - const DateTimeType type; - static DateTime* create(const Locale&, DateTimeType, UErrorCode&); - DateTime(const Locale& l, DateTimeType t) : locale(l), type(t) {} + const DateTimeFactory::DateTimeType type; + static DateTime* create(const Locale&, + DateTimeFactory::DateTimeType, + UErrorCode&); + DateTime(const Locale& l, DateTimeFactory::DateTimeType t) + : locale(l), type(t) {} const LocalPointer icuFormatter; }; class NumberValue; + class NumberFactory : public FunctionFactory { + public: + Function* createFunction(const Locale& locale, UErrorCode& status) override; + static NumberFactory* integer(UErrorCode& success); + static NumberFactory* number(UErrorCode& success); + virtual ~NumberFactory(); + private: + static NumberFactory* create(bool, UErrorCode&); + NumberFactory(bool isInt) : isInteger(isInt) {} + bool isInteger; + }; // class NumberFactory + class Number : public Function { public: static Number* integer(const Locale& loc, UErrorCode& success); @@ -134,10 +166,18 @@ namespace message2 { friend class DateTime; UnicodeString formattedDate; - DateTimeValue(DateTime::DateTimeType type, const Locale&, + DateTimeValue(const Locale& locale, DateTimeFactory::DateTimeType type, FunctionValue&, FunctionOptions&&, UErrorCode&); }; // class DateTimeValue + class StringFactory : public FunctionFactory { + public: + Function* createFunction(const Locale& locale, UErrorCode& status) override; + static StringFactory* string(UErrorCode& status); + virtual ~StringFactory(); + private: + }; // class StringFactory + class String : public Function { public: FunctionValue* call(FunctionValue& val, diff --git a/icu4c/source/i18n/unicode/messageformat2.h b/icu4c/source/i18n/unicode/messageformat2.h index e3497c23bc52..f1ecfa91fb21 100644 --- a/icu4c/source/i18n/unicode/messageformat2.h +++ b/icu4c/source/i18n/unicode/messageformat2.h @@ -374,7 +374,8 @@ namespace message2 { bool isBuiltInFunction(const FunctionName&) const; bool isFunction(const FunctionName& fn) const { return isBuiltInFunction(fn) || isCustomFunction(fn); } void setNotSelectableError(MessageContext&, const InternalValue&, UErrorCode&) const; - Function* lookupFunction(const FunctionName&, UErrorCode&) const; + // Result is not adopted + FunctionFactory* lookupFunctionFactory(const FunctionName&, UErrorCode&) const; bool getDefaultFormatterNameByType(const UnicodeString&, FunctionName&) const; // Checking for resolution errors diff --git a/icu4c/source/i18n/unicode/messageformat2_function_registry.h b/icu4c/source/i18n/unicode/messageformat2_function_registry.h index 81aa1f452ffa..f76fca6d580b 100644 --- a/icu4c/source/i18n/unicode/messageformat2_function_registry.h +++ b/icu4c/source/i18n/unicode/messageformat2_function_registry.h @@ -28,7 +28,7 @@ namespace message2 { using namespace data_model; - class Function; + class FunctionFactory; /** * Defines mappings from names of formatters and selectors to functions implementing them. @@ -47,19 +47,19 @@ namespace message2 { public: /** - * Looks up a function by the name of the function. The result is non-const, + * Looks up a function factory by the name of the function. The result is non-const, * since functions may have local state. Returns the result by pointer * rather than by reference since it can fail. * * @param functionName Name of the desired function. - * @return A pointer to the Function registered under `functionName`, or null + * @return A pointer to the function factory registered under `functionName`, or null * if no function was registered under that name. The pointer is not owned * by the caller. * * @internal ICU 75 technology preview * @deprecated This API is for technology preview only. */ - Function* getFunction(const FunctionName& functionName) const; + FunctionFactory* getFunction(const FunctionName& functionName) const; /** * Looks up a function by a type tag. This method gets the name of the default formatter registered * for that type. If no formatter was explicitly registered for this type, it returns false. @@ -124,9 +124,9 @@ namespace message2 { * @internal ICU 77 technology preview * @deprecated This API is for technology preview only. */ - Builder& adoptFunction(const data_model::FunctionName& functionName, - Function* function, - UErrorCode& errorCode); + Builder& adoptFunctionFactory(const data_model::FunctionName& functionName, + FunctionFactory* function, + UErrorCode& errorCode); /** * Registers a formatter factory to a given type tag. * (See `FormattableObject` for details on type tags.) @@ -226,6 +226,44 @@ namespace message2 { Hashtable* formattersByType = nullptr; }; // class MFFunctionRegistry + class Function; + + /** + * Interface that function factory classes must implement. + * + * @internal ICU 77 technology preview + * @deprecated This API is for technology preview only. + */ + class U_I18N_API FunctionFactory : public UObject { + public: + /** + * Constructs a new function object. This method is not const; + * function factories with local state may be defined. + * + * @param locale Locale to be used by the function. + * @param status Input/output error code. + * @return The new Formatter, which is non-null if U_SUCCESS(status). + * + * @internal ICU 75 technology preview + * @deprecated This API is for technology preview only. + */ + virtual Function* createFunction(const Locale& locale, UErrorCode& status) = 0; + /** + * Destructor. + * + * @internal ICU 75 technology preview + * @deprecated This API is for technology preview only. + */ + virtual ~FunctionFactory(); + /** + * Copy constructor. + * + * @internal ICU 75 technology preview + * @deprecated This API is for technology preview only. + */ + FunctionFactory& operator=(const FunctionFactory&) = delete; + }; // class FunctionFactory + class FunctionValue; /** diff --git a/icu4c/source/test/intltest/messageformat2test.cpp b/icu4c/source/test/intltest/messageformat2test.cpp index 0c42c83f0ecd..a7f6d727addb 100644 --- a/icu4c/source/test/intltest/messageformat2test.cpp +++ b/icu4c/source/test/intltest/messageformat2test.cpp @@ -278,7 +278,7 @@ void TestMessageFormat2::testAPICustomFunctions() { // Set up custom function registry MFFunctionRegistry::Builder builder(errorCode); MFFunctionRegistry functionRegistry = - builder.adoptFunction(data_model::FunctionName("person"), new PersonNameFunction(), errorCode) + builder.adoptFunctionFactory(data_model::FunctionName("person"), new PersonNameFactory(), errorCode) .build(); Person* person = new Person(UnicodeString("Mr."), UnicodeString("John"), UnicodeString("Doe")); @@ -320,8 +320,8 @@ void TestMessageFormat2::testAPICustomFunctions() { MFFunctionRegistry::Builder builderByType(errorCode); FunctionName personFunctionName("person"); MFFunctionRegistry functionRegistryByType = - builderByType.adoptFunction(personFunctionName, - new PersonNameFunction(), + builderByType.adoptFunctionFactory(personFunctionName, + new PersonNameFactory(), errorCode) .setDefaultFormatterNameByType("person", personFunctionName, diff --git a/icu4c/source/test/intltest/messageformat2test.h b/icu4c/source/test/intltest/messageformat2test.h index 5bee2dc0317e..f675e4a22431 100644 --- a/icu4c/source/test/intltest/messageformat2test.h +++ b/icu4c/source/test/intltest/messageformat2test.h @@ -112,10 +112,20 @@ class Person : public FormattableObject { const UnicodeString tagName; }; +class PersonNameFactory : public FunctionFactory { + Function* createFunction(const Locale& locale, UErrorCode& status) override; + virtual ~PersonNameFactory(); +}; + class PersonNameFunction : public Function { public: FunctionValue* call(FunctionValue&, FunctionOptions&&, UErrorCode&) override; virtual ~PersonNameFunction(); + private: + friend class PersonNameFactory; + + const Locale locale; + PersonNameFunction(const Locale& loc) : locale(loc) {} }; class PersonNameValue : public FunctionValue { @@ -142,6 +152,11 @@ class FormattableProperties : public FormattableObject { const UnicodeString tagName; }; +class GrammarCasesFactory : public FunctionFactory { + Function* createFunction(const Locale& locale, UErrorCode& status) override; + virtual ~GrammarCasesFactory(); +}; + class GrammarCasesFunction : public Function { public: FunctionValue* call(FunctionValue&, FunctionOptions&&, UErrorCode&) override; @@ -161,6 +176,11 @@ class GrammarCasesValue : public FunctionValue { void getDativeAndGenitive(const UnicodeString&, UnicodeString& result) const; }; // class GrammarCasesValue +class ListFactory : public FunctionFactory { + Function* createFunction(const Locale& locale, UErrorCode& status) override; + virtual ~ListFactory(); +}; + class ListFunction : public Function { public: FunctionValue* call(FunctionValue&, FunctionOptions&&, UErrorCode&) override; @@ -185,6 +205,11 @@ class ListValue : public FunctionValue { UErrorCode&); }; // class ListValue +class NounFunctionFactory : public FunctionFactory { + Function* createFunction(const Locale& locale, UErrorCode& status) override; + virtual ~NounFunctionFactory(); +}; + class NounValue : public FunctionValue { public: UnicodeString formatToString(UErrorCode&) const override; @@ -199,6 +224,11 @@ class NounValue : public FunctionValue { UErrorCode&); }; // class NounValue +class AdjectiveFunctionFactory : public FunctionFactory { + Function* createFunction(const Locale& locale, UErrorCode& status) override; + virtual ~AdjectiveFunctionFactory(); +}; + class AdjectiveValue : public FunctionValue { public: UnicodeString formatToString(UErrorCode&) const override; diff --git a/icu4c/source/test/intltest/messageformat2test_custom.cpp b/icu4c/source/test/intltest/messageformat2test_custom.cpp index db7adb5852b3..8a076f295dcf 100644 --- a/icu4c/source/test/intltest/messageformat2test_custom.cpp +++ b/icu4c/source/test/intltest/messageformat2test_custom.cpp @@ -32,7 +32,9 @@ void TestMessageFormat2::testPersonFormatter(IcuTestErrorCode& errorCode) { CHECK_ERROR(errorCode); MFFunctionRegistry customRegistry(MFFunctionRegistry::Builder(errorCode) - .adoptFunction(FunctionName("person"), new PersonNameFunction(), errorCode) + .adoptFunctionFactory(FunctionName("person"), + new PersonNameFactory(), + errorCode) .build()); UnicodeString name = "name"; LocalPointer person(new Person(UnicodeString("Mr."), UnicodeString("John"), UnicodeString("Doe"))); @@ -98,7 +100,9 @@ void TestMessageFormat2::testCustomFunctionsComplexMessage(IcuTestErrorCode& err CHECK_ERROR(errorCode); MFFunctionRegistry customRegistry(MFFunctionRegistry::Builder(errorCode) - .adoptFunction(FunctionName("person"), new PersonNameFunction(), errorCode) + .adoptFunctionFactory(FunctionName("person"), + new PersonNameFactory(), + errorCode) .build()); UnicodeString host = "host"; UnicodeString hostGender = "hostGender"; @@ -188,8 +192,12 @@ void TestMessageFormat2::testComplexOptions(IcuTestErrorCode& errorCode) { CHECK_ERROR(errorCode); MFFunctionRegistry customRegistry(MFFunctionRegistry::Builder(errorCode) - .adoptFunction(FunctionName("noun"), new NounFunction(), errorCode) - .adoptFunction(FunctionName("adjective"), new AdjectiveFunction(), errorCode) + .adoptFunctionFactory(FunctionName("noun"), + new NounFunctionFactory(), + errorCode) + .adoptFunctionFactory(FunctionName("adjective"), + new AdjectiveFunctionFactory(), + errorCode) .build()); UnicodeString name = "name"; TestCase::Builder testBuilder; @@ -265,6 +273,16 @@ static bool hasStringOption(const FunctionOptionsMap& opt, return getStringOption(opt, k) == v; } +Function* PersonNameFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + PersonNameFunction* result = new PersonNameFunction(locale); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + FunctionValue* PersonNameFunction::call(FunctionValue& arg, FunctionOptions&& opts, UErrorCode& errorCode) { @@ -349,6 +367,7 @@ PersonNameValue::PersonNameValue(FunctionValue& arg, FormattableProperties::~FormattableProperties() {} Person::~Person() {} +PersonNameFactory::~PersonNameFactory() {} PersonNameValue::~PersonNameValue() {} /* @@ -379,9 +398,21 @@ PersonNameValue::~PersonNameValue() {} result += postfix; } +Function* GrammarCasesFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + (void) locale; + + GrammarCasesFunction* result = new GrammarCasesFunction(); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + FunctionValue* GrammarCasesFunction::call(FunctionValue& arg, - FunctionOptions&& opts, - UErrorCode& errorCode) { + FunctionOptions&& opts, + UErrorCode& errorCode) { NULL_ON_ERROR(errorCode); GrammarCasesValue* v = new GrammarCasesValue(arg, std::move(opts), errorCode); @@ -444,7 +475,7 @@ void TestMessageFormat2::testGrammarCasesFormatter(IcuTestErrorCode& errorCode) CHECK_ERROR(errorCode); MFFunctionRegistry customRegistry = MFFunctionRegistry::Builder(errorCode) - .adoptFunction(FunctionName("grammarBB"), new GrammarCasesFunction(), errorCode) + .adoptFunctionFactory(FunctionName("grammarBB"), new GrammarCasesFactory(), errorCode) .build(); TestCase::Builder testBuilder; @@ -496,12 +527,26 @@ void TestMessageFormat2::testGrammarCasesFormatter(IcuTestErrorCode& errorCode) TestUtils::runTestCase(*this, test, errorCode); } +GrammarCasesFactory::~GrammarCasesFactory() {} GrammarCasesValue::~GrammarCasesValue() {} /* See ICU4J: CustomFormatterListTest.java */ +Function* ListFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + (void) locale; + + ListFunction* result = new ListFunction(locale); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + + FunctionValue* ListFunction::call(FunctionValue& arg, FunctionOptions&& opts, UErrorCode& errorCode) { @@ -585,6 +630,7 @@ message2::ListValue::ListValue(const Locale& locale, } } +ListFactory::~ListFactory() {} ListValue::~ListValue() {} ListFunction::~ListFunction() {} @@ -601,7 +647,7 @@ void TestMessageFormat2::testListFormatter(IcuTestErrorCode& errorCode) { TestCase::Builder testBuilder; MFFunctionRegistry reg = MFFunctionRegistry::Builder(errorCode) - .adoptFunction(FunctionName("listformat"), new ListFunction(Locale("en")), errorCode) + .adoptFunctionFactory(FunctionName("listformat"), new ListFactory(), errorCode) .build(); CHECK_ERROR(errorCode); @@ -826,6 +872,18 @@ void TestMessageFormat2::testMessageRefFormatter(IcuTestErrorCode& errorCode) { } #endif +Function* NounFunctionFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + (void) locale; + + NounFunction* result = new NounFunction(); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + FunctionValue* NounFunction::call(FunctionValue& arg, FunctionOptions&& opts, UErrorCode& errorCode) { @@ -881,6 +939,18 @@ NounValue::NounValue(FunctionValue& arg, } } +Function* AdjectiveFunctionFactory::createFunction(const Locale& locale, UErrorCode& errorCode) { + NULL_ON_ERROR(errorCode); + + (void) locale; + + AdjectiveFunction* result = new AdjectiveFunction(); + if (result == nullptr) { + errorCode = U_MEMORY_ALLOCATION_ERROR; + } + return result; +} + FunctionValue* AdjectiveFunction::call(FunctionValue& arg, FunctionOptions&& opts, UErrorCode& errorCode) { @@ -946,6 +1016,8 @@ AdjectiveValue::AdjectiveValue(FunctionValue& arg, } } +NounFunctionFactory::~NounFunctionFactory() {} +AdjectiveFunctionFactory::~AdjectiveFunctionFactory() {} NounFunction::~NounFunction() {} AdjectiveFunction::~AdjectiveFunction() {} NounValue::~NounValue() {}