aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/icu/i18n/messageformat2_formattable.cpp
diff options
context:
space:
mode:
authorromankoshelev <romankoshelev@yandex-team.com>2024-05-13 11:00:27 +0300
committerromankoshelev <romankoshelev@yandex-team.com>2024-05-13 11:13:05 +0300
commit5b22fadb0f035a3b82c328e0ae710ad2b92f6eac (patch)
treee15dc649c79c4fb78f35cd6694dfe9af9bfcc0ad /contrib/libs/icu/i18n/messageformat2_formattable.cpp
parent5946aa7d3cbca62f6bcf074e8a2b9346e7a96af4 (diff)
downloadydb-5b22fadb0f035a3b82c328e0ae710ad2b92f6eac.tar.gz
Update ICU to 75.1
904da4ae1c86fc5542eac7f1cd18d97b72eb8517
Diffstat (limited to 'contrib/libs/icu/i18n/messageformat2_formattable.cpp')
-rw-r--r--contrib/libs/icu/i18n/messageformat2_formattable.cpp338
1 files changed, 338 insertions, 0 deletions
diff --git a/contrib/libs/icu/i18n/messageformat2_formattable.cpp b/contrib/libs/icu/i18n/messageformat2_formattable.cpp
new file mode 100644
index 0000000000..3152ccb44f
--- /dev/null
+++ b/contrib/libs/icu/i18n/messageformat2_formattable.cpp
@@ -0,0 +1,338 @@
+// © 2024 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#if !UCONFIG_NO_MF2
+
+#include "unicode/messageformat2_formattable.h"
+#include "unicode/smpdtfmt.h"
+#include "messageformat2_macros.h"
+
+#include "limits.h"
+
+U_NAMESPACE_BEGIN
+
+namespace message2 {
+
+ // Fallback values are enclosed in curly braces;
+ // see https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#formatting-fallback-values
+
+ static UnicodeString fallbackToString(const UnicodeString& s) {
+ UnicodeString result;
+ result += LEFT_CURLY_BRACE;
+ result += s;
+ result += RIGHT_CURLY_BRACE;
+ return result;
+ }
+
+ Formattable& Formattable::operator=(Formattable other) noexcept {
+ swap(*this, other);
+ return *this;
+ }
+
+ Formattable::Formattable(const Formattable& other) {
+ contents = other.contents;
+ holdsDate = other.holdsDate;
+ }
+
+ Formattable Formattable::forDecimal(std::string_view number, UErrorCode &status) {
+ Formattable f;
+ // The relevant overload of the StringPiece constructor
+ // casts the string length to int32_t, so we have to check
+ // that the length makes sense
+ if (number.size() > INT_MAX) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ f.contents = icu::Formattable(StringPiece(number), status);
+ }
+ return f;
+ }
+
+ UFormattableType Formattable::getType() const {
+ if (std::holds_alternative<double>(contents)) {
+ return holdsDate ? UFMT_DATE : UFMT_DOUBLE;
+ }
+ if (std::holds_alternative<int64_t>(contents)) {
+ return UFMT_INT64;
+ }
+ if (std::holds_alternative<UnicodeString>(contents)) {
+ return UFMT_STRING;
+ }
+ if (isDecimal()) {
+ switch (std::get_if<icu::Formattable>(&contents)->getType()) {
+ case icu::Formattable::Type::kLong: {
+ return UFMT_LONG;
+ }
+ case icu::Formattable::Type::kDouble: {
+ return UFMT_DOUBLE;
+ }
+ default: {
+ return UFMT_INT64;
+ }
+ }
+ }
+ if (std::holds_alternative<const FormattableObject*>(contents)) {
+ return UFMT_OBJECT;
+ }
+ return UFMT_ARRAY;
+ }
+
+ const Formattable* Formattable::getArray(int32_t& len, UErrorCode& status) const {
+ NULL_ON_ERROR(status);
+
+ if (getType() != UFMT_ARRAY) {
+ len = 0;
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ const std::pair<const Formattable*, int32_t>& p = *std::get_if<std::pair<const Formattable*, int32_t>>(&contents);
+ U_ASSERT(p.first != nullptr);
+ len = p.second;
+ return p.first;
+ }
+
+ int64_t Formattable::getInt64(UErrorCode& status) const {
+ if (isDecimal() && isNumeric()) {
+ return std::get_if<icu::Formattable>(&contents)->getInt64(status);
+ }
+
+ switch (getType()) {
+ case UFMT_LONG:
+ case UFMT_INT64: {
+ return *std::get_if<int64_t>(&contents);
+ }
+ case UFMT_DOUBLE: {
+ return icu::Formattable(*std::get_if<double>(&contents)).getInt64(status);
+ }
+ default: {
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ icu::Formattable Formattable::asICUFormattable(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return {};
+ }
+ // Type must not be UFMT_ARRAY or UFMT_OBJECT
+ if (getType() == UFMT_ARRAY || getType() == UFMT_OBJECT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return {};
+ }
+
+ if (isDecimal()) {
+ return *std::get_if<icu::Formattable>(&contents);
+ }
+
+ switch (getType()) {
+ case UFMT_DATE: {
+ return icu::Formattable(*std::get_if<double>(&contents), icu::Formattable::kIsDate);
+ }
+ case UFMT_DOUBLE: {
+ return icu::Formattable(*std::get_if<double>(&contents));
+ }
+ case UFMT_LONG: {
+ return icu::Formattable(static_cast<int32_t>(*std::get_if<double>(&contents)));
+ }
+ case UFMT_INT64: {
+ return icu::Formattable(*std::get_if<int64_t>(&contents));
+ }
+ case UFMT_STRING: {
+ return icu::Formattable(*std::get_if<UnicodeString>(&contents));
+ }
+ default: {
+ // Already checked for UFMT_ARRAY and UFMT_OBJECT
+ return icu::Formattable();
+ }
+ }
+ }
+
+ Formattable::~Formattable() {}
+
+ FormattableObject::~FormattableObject() {}
+
+ FormattedMessage::~FormattedMessage() {}
+
+ FormattedValue::FormattedValue(const UnicodeString& s) {
+ type = kString;
+ stringOutput = std::move(s);
+ }
+
+ FormattedValue::FormattedValue(number::FormattedNumber&& n) {
+ type = kNumber;
+ numberOutput = std::move(n);
+ }
+
+ FormattedValue& FormattedValue::operator=(FormattedValue&& other) noexcept {
+ type = other.type;
+ if (type == kString) {
+ stringOutput = std::move(other.stringOutput);
+ } else {
+ numberOutput = std::move(other.numberOutput);
+ }
+ return *this;
+ }
+
+ FormattedValue::~FormattedValue() {}
+
+ FormattedPlaceholder& FormattedPlaceholder::operator=(FormattedPlaceholder&& other) noexcept {
+ type = other.type;
+ source = other.source;
+ if (type == kEvaluated) {
+ formatted = std::move(other.formatted);
+ previousOptions = std::move(other.previousOptions);
+ }
+ fallback = other.fallback;
+ return *this;
+ }
+
+ const Formattable& FormattedPlaceholder::asFormattable() const {
+ return source;
+ }
+
+ // Default formatters
+ // ------------------
+
+ number::FormattedNumber formatNumberWithDefaults(const Locale& locale, double toFormat, UErrorCode& errorCode) {
+ return number::NumberFormatter::withLocale(locale).formatDouble(toFormat, errorCode);
+ }
+
+ number::FormattedNumber formatNumberWithDefaults(const Locale& locale, int32_t toFormat, UErrorCode& errorCode) {
+ return number::NumberFormatter::withLocale(locale).formatInt(toFormat, errorCode);
+ }
+
+ number::FormattedNumber formatNumberWithDefaults(const Locale& locale, int64_t toFormat, UErrorCode& errorCode) {
+ return number::NumberFormatter::withLocale(locale).formatInt(toFormat, errorCode);
+ }
+
+ number::FormattedNumber formatNumberWithDefaults(const Locale& locale, StringPiece toFormat, UErrorCode& errorCode) {
+ return number::NumberFormatter::withLocale(locale).formatDecimal(toFormat, errorCode);
+ }
+
+ DateFormat* defaultDateTimeInstance(const Locale& locale, UErrorCode& errorCode) {
+ NULL_ON_ERROR(errorCode);
+ LocalPointer<DateFormat> df(DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::SHORT, locale));
+ if (!df.isValid()) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return df.orphan();
+ }
+
+ void formatDateWithDefaults(const Locale& locale, UDate date, UnicodeString& result, UErrorCode& errorCode) {
+ CHECK_ERROR(errorCode);
+
+ LocalPointer<DateFormat> df(defaultDateTimeInstance(locale, errorCode));
+ CHECK_ERROR(errorCode);
+ df->format(date, result, 0, errorCode);
+ }
+
+ // Called when output is required and the contents are an unevaluated `Formattable`;
+ // formats the source `Formattable` to a string with defaults, if it can be
+ // formatted with a default formatter
+ static FormattedPlaceholder formatWithDefaults(const Locale& locale, const FormattedPlaceholder& input, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return {};
+ }
+
+ const Formattable& toFormat = input.asFormattable();
+ // Try as decimal number first
+ if (toFormat.isNumeric()) {
+ // Note: the ICU Formattable has to be created here since the StringPiece
+ // refers to state inside the Formattable; so otherwise we'll have a reference
+ // to a temporary object
+ icu::Formattable icuFormattable = toFormat.asICUFormattable(status);
+ StringPiece asDecimal = icuFormattable.getDecimalNumber(status);
+ if (U_FAILURE(status)) {
+ return {};
+ }
+ if (asDecimal != nullptr) {
+ return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, asDecimal, status)));
+ }
+ }
+
+ UFormattableType type = toFormat.getType();
+ switch (type) {
+ case UFMT_DATE: {
+ UnicodeString result;
+ UDate d = toFormat.getDate(status);
+ U_ASSERT(U_SUCCESS(status));
+ formatDateWithDefaults(locale, d, result, status);
+ return FormattedPlaceholder(input, FormattedValue(std::move(result)));
+ }
+ case UFMT_DOUBLE: {
+ double d = toFormat.getDouble(status);
+ U_ASSERT(U_SUCCESS(status));
+ return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, d, status)));
+ }
+ case UFMT_LONG: {
+ int32_t l = toFormat.getLong(status);
+ U_ASSERT(U_SUCCESS(status));
+ return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, l, status)));
+ }
+ case UFMT_INT64: {
+ int64_t i = toFormat.getInt64Value(status);
+ U_ASSERT(U_SUCCESS(status));
+ return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, i, status)));
+ }
+ case UFMT_STRING: {
+ const UnicodeString& s = toFormat.getString(status);
+ U_ASSERT(U_SUCCESS(status));
+ return FormattedPlaceholder(input, FormattedValue(UnicodeString(s)));
+ }
+ default: {
+ // No default formatters for other types; use fallback
+ status = U_MF_FORMATTING_ERROR;
+ // Note: it would be better to set an internal formatting error so that a string
+ // (e.g. the type tag) can be provided. However, this method is called by the
+ // public method formatToString() and thus can't take a MessageContext
+ return FormattedPlaceholder(input.getFallback());
+ }
+ }
+ }
+
+ // Called when string output is required; forces output to be produced
+ // if none is present (including formatting number output as a string)
+ UnicodeString FormattedPlaceholder::formatToString(const Locale& locale,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return {};
+ }
+ if (isFallback() || isNullOperand()) {
+ return fallbackToString(fallback);
+ }
+
+ // Evaluated value: either just return the string, or format the number
+ // as a string and return it
+ if (isEvaluated()) {
+ if (formatted.isString()) {
+ return formatted.getString();
+ } else {
+ return formatted.getNumber().toString(status);
+ }
+ }
+ // Unevaluated value: first evaluate it fully, then format
+ UErrorCode savedStatus = status;
+ FormattedPlaceholder evaluated = formatWithDefaults(locale, *this, status);
+ if (status == U_MF_FORMATTING_ERROR) {
+ U_ASSERT(evaluated.isFallback());
+ return evaluated.getFallback();
+ }
+ // Ignore U_USING_DEFAULT_WARNING
+ if (status == U_USING_DEFAULT_WARNING) {
+ status = savedStatus;
+ }
+ return evaluated.formatToString(locale, status);
+ }
+
+} // namespace message2
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_MF2 */
+
+#endif /* #if !UCONFIG_NO_FORMATTING */