/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/icu-small/source/i18n/messageformat2_data_model.cpp
928 строк
25 KB
Node.js GitHub Bot
deps: update icu to 78.2
11 янв 2026, 21:05
Не верифицирован
11 янв 2026, 21:05
1bd7f62
Код
Авторство
О чём код?
// © 2024 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_NORMALIZATION #if !UCONFIG_NO_FORMATTING #if !UCONFIG_NO_MF2 #include "unicode/messageformat2_data_model.h" #include "messageformat2_allocation.h" #include "messageformat2_macros.h" #include "uvector.h" U_NAMESPACE_BEGIN namespace message2 { namespace data_model { // Implementation //------------------ SelectorKeys const Key* SelectorKeys::getKeysInternal() const { return keys.getAlias(); } // Lexically order key lists bool SelectorKeys::operator<(const SelectorKeys& other) const { // Handle key lists of different sizes first -- // this case does have to be handled (even though it would // reflect a data model error) because of the need to produce // partial output if (len < other.len) { return true; } if (len > other.len) { return false; } for (int32_t i = 0; i < len; i++) { if (keys[i] < other.keys[i]) { return true; } if (!(keys[i] == other.keys[i])) { return false; } } // If we've reached here, all keys must be equal return false; } SelectorKeys::Builder::Builder(UErrorCode& status) { keys = createUVector(status); } SelectorKeys::Builder& SelectorKeys::Builder::add(Key&& key, UErrorCode& status) noexcept { U_ASSERT(keys != nullptr); if (U_SUCCESS(status)) { Key* k = create<Key>(std::move(key), status); keys->adoptElement(k, status); } return *this; } SelectorKeys SelectorKeys::Builder::build(UErrorCode& status) const { if (U_FAILURE(status)) { return {}; } U_ASSERT(keys != nullptr); return SelectorKeys(*keys, status); } SelectorKeys::Builder::~Builder() { if (keys != nullptr) { delete keys; } } SelectorKeys::SelectorKeys(const UVector& ks, UErrorCode& status) : len(ks.size()) { Key* result = copyVectorToArray<Key>(ks, status); if (U_FAILURE(status)) { return; } keys.adoptInstead(result); } SelectorKeys& SelectorKeys::operator=(SelectorKeys other) noexcept { swap(*this, other); return *this; } SelectorKeys::SelectorKeys(const SelectorKeys& other) : len(other.len) { UErrorCode localErrorCode = U_ZERO_ERROR; if (len != 0) { keys.adoptInstead(copyArray(other.keys.getAlias(), len, localErrorCode)); } if (U_FAILURE(localErrorCode)) { len = 0; } } SelectorKeys::~SelectorKeys() { len = 0; } //------------------ Literal bool Literal::operator<(const Literal& other) const { // Ignore quoting for the purposes of ordering return contents < other.contents; } bool Literal::operator==(const Literal& other) const { // Ignore quoting for the purposes of ordering return contents == other.contents; } UnicodeString Literal::quoted() const { UnicodeString result(PIPE); result += unquoted(); result += PIPE; return result; } const UnicodeString& Literal::unquoted() const { return contents; } Literal& Literal::operator=(Literal other) noexcept { swap(*this, other); return *this; } Literal::~Literal() { thisIsQuoted = false; } //------------------ Operand Operand::Operand(const Operand& other) : contents(other.contents) {} Operand& Operand::operator=(Operand other) noexcept { swap(*this, other); return *this; } UBool Operand::isVariable() const { return (contents.has_value() && std::holds_alternative<VariableName>(*contents)); } UBool Operand::isLiteral() const { return (contents.has_value() && std::holds_alternative<Literal>(*contents)); } UBool Operand::isNull() const { return !contents.has_value(); } const Literal& Operand::asLiteral() const { U_ASSERT(isLiteral()); return *(std::get_if<Literal>(&(*contents))); } const VariableName& Operand::asVariable() const { U_ASSERT(isVariable()); return *(std::get_if<VariableName>(&(*contents))); } Operand::~Operand() {} //---------------- Key Key& Key::operator=(Key other) noexcept { swap(*this, other); return *this; } bool Key::operator<(const Key& other) const { // Arbitrarily treat * as greater than all concrete keys if (isWildcard()) { return false; } if (other.isWildcard()) { return true; } return (asLiteral() < other.asLiteral()); } bool Key::operator==(const Key& other) const { if (isWildcard()) { return other.isWildcard(); } if (other.isWildcard()) { return false; } return (asLiteral() == other.asLiteral()); } const Literal& Key::asLiteral() const { U_ASSERT(!isWildcard()); return *contents; } Key::~Key() {} //------------------------ Operator OptionMap::OptionMap(const UVector& opts, UErrorCode& status) : len(opts.size()) { Option* result = copyVectorToArray<Option>(opts, status); if (U_FAILURE(status)) { bogus = true; return; } options.adoptInstead(result); bogus = false; } OptionMap::OptionMap(const OptionMap& other) : len(other.len) { U_ASSERT(!other.bogus); if (len == 0) { bogus = false; return; } UErrorCode localErrorCode = U_ZERO_ERROR; Option* result = copyArray(other.options.getAlias(), len, localErrorCode); if (U_FAILURE(localErrorCode)) { bogus = true; return; } bogus = false; options.adoptInstead(result); } OptionMap& OptionMap::operator=(OptionMap other) { swap(*this, other); return *this; } const Option& OptionMap::getOption(int32_t i, UErrorCode& status) const { if (U_FAILURE(status) || bogus) { if (bogus) { status = U_MEMORY_ALLOCATION_ERROR; } } else { U_ASSERT(options.isValid()); U_ASSERT(i < len); } return options[i]; } int32_t OptionMap::size() const { U_ASSERT(options.isValid() || len == 0); return len; } OptionMap::~OptionMap() {} OptionMap OptionMap::Builder::build(UErrorCode& status) { return OptionMap(*options, status); } OptionMap::Builder::Builder(UErrorCode& status) { options = createStringUVector(status); } OptionMap::Builder::Builder(OptionMap::Builder&& other) { checkDuplicates = other.checkDuplicates; options = other.options; other.options = nullptr; } OptionMap::Builder& OptionMap::Builder::operator=(OptionMap::Builder other) noexcept { swap(*this, other); return *this; } /* static */ OptionMap::Builder OptionMap::Builder::attributes(UErrorCode& status) { Builder b(status); // The same code is re-used for representing attributes and options. // Duplicate attributes are allowed, while duplicate options are disallowed. b.checkDuplicates = false; return b; } static UBool hasOptionNamed(const UVector& v, const UnicodeString& s) { for (int32_t i = 0; i < v.size(); i++) { const Option* opt = static_cast<Option*>(v[i]); U_ASSERT(opt != nullptr); if (opt->getName() == s) { return true; } } return false; } OptionMap::Builder& OptionMap::Builder::add(Option&& opt, UErrorCode& status) { THIS_ON_ERROR(status); // If the option name is already in the map, emit a data model error if (checkDuplicates && hasOptionNamed(*options, opt.getName())) { status = U_MF_DUPLICATE_OPTION_NAME_ERROR; } else { Option* newOption = create<Option>(std::move(opt), status); options->adoptElement(newOption, status); } return *this; } OptionMap::Builder::~Builder() { if (options != nullptr) { delete options; } } const OptionMap& Operator::getOptionsInternal() const { return options; } Option::Option(const Option& other): name(other.name), rand(other.rand) {} Option& Option::operator=(Option other) noexcept { swap(*this, other); return *this; } Option::~Option() {} Operator::Builder::Builder(UErrorCode& status) : options(OptionMap::Builder(status)) {} Operator::Builder& Operator::Builder::setFunctionName(FunctionName&& func) { functionName = std::move(func); return *this; } const FunctionName& Operator::getFunctionName() const { return name; } Operator::Builder& Operator::Builder::addOption(const UnicodeString &key, Operand&& value, UErrorCode& errorCode) noexcept { THIS_ON_ERROR(errorCode); options.add(Option(key, std::move(value)), errorCode); return *this; } Operator Operator::Builder::build(UErrorCode& errorCode) { return Operator(functionName, options.build(errorCode)); } Operator::Operator(const Operator& other) noexcept : name(other.name), options(other.options) {} Operator& Operator::operator=(Operator other) noexcept { swap(*this, other); return *this; } // Function call Operator::Operator(const FunctionName& f, const OptionMap& opts) : name(f), options(opts) {} Operator::Builder::~Builder() {} Operator::~Operator() {} // ------------ Markup Markup::Builder::Builder(UErrorCode& status) : options(OptionMap::Builder(status)), attributes(OptionMap::Builder::attributes(status)) {} Markup::Markup(UMarkupType ty, UnicodeString n, OptionMap&& o, OptionMap&& a) : type(ty), name(n), options(std::move(o)), attributes(std::move(a)) {} Markup::Builder& Markup::Builder::addOption(const UnicodeString &key, Operand&& value, UErrorCode& errorCode) { options.add(Option(key, std::move(value)), errorCode); return *this; } Markup::Builder& Markup::Builder::addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& errorCode) { attributes.add(Option(key, std::move(value)), errorCode); return *this; } Markup Markup::Builder::build(UErrorCode& errorCode) { Markup result; if (U_FAILURE(errorCode)) { return result; } if (type == UMARKUP_COUNT || name.length() == 0) { // One of `setOpen()`, `setClose()`, or `setStandalone()` // must be called before calling build() // setName() must be called before calling build() errorCode = U_INVALID_STATE_ERROR; } else { result = Markup(type, name, options.build(errorCode), attributes.build(errorCode)); } return result; } Markup::Builder::~Builder() {} Markup::~Markup() {} // ------------ Expression Expression::Builder::Builder(UErrorCode& status) : attributes(OptionMap::Builder::attributes(status)) {} UBool Expression::isStandaloneAnnotation() const { return rand.isNull(); } // Returns true for function calls with operands as well as // standalone annotations. UBool Expression::isFunctionCall() const { return rator.has_value(); } const Operator* Expression::getOperator(UErrorCode& status) const { NULL_ON_ERROR(status); if (!isFunctionCall()) { status = U_INVALID_STATE_ERROR; return nullptr; } U_ASSERT(rator); return &(*rator); } // May return null operand const Operand& Expression::getOperand() const { return rand; } Expression::Builder& Expression::Builder::setOperand(Operand&& rAnd) { hasOperand = true; rand = std::move(rAnd); return *this; } Expression::Builder& Expression::Builder::setOperator(Operator&& rAtor) { hasOperator = true; rator = std::move(rAtor); return *this; } Expression::Builder& Expression::Builder::addAttribute(const UnicodeString& k, Operand&& v, UErrorCode& status) { attributes.add(Option(k, std::move(v)), status); return *this; } Expression Expression::Builder::build(UErrorCode& errorCode) { Expression result; if (U_FAILURE(errorCode)) { return result; } if ((!hasOperand || rand.isNull()) && !hasOperator) { errorCode = U_INVALID_STATE_ERROR; return result; } OptionMap attributeMap = attributes.build(errorCode); if (hasOperand && hasOperator) { result = Expression(rator, rand, std::move(attributeMap)); } else if (hasOperand && !hasOperator) { result = Expression(rand, std::move(attributeMap)); } else { // rator is valid, rand is not valid result = Expression(rator, std::move(attributeMap)); } return result; } Expression::Expression() : rator(std::nullopt) {} Expression::Expression(const Expression& other) : rator(other.rator), rand(other.rand), attributes(other.attributes) {} Expression& Expression::operator=(Expression other) noexcept { swap(*this, other); return *this; } Expression::Builder::~Builder() {} Expression::~Expression() {} // ----------- PatternPart // PatternPart needs a copy constructor in order to make Pattern deeply copyable // If !isRawText and the copy of the other expression fails, // then isBogus() will be true for this PatternPart PatternPart::PatternPart(const PatternPart& other) : piece(other.piece) {} const Expression& PatternPart::contents() const { U_ASSERT(isExpression()); return *std::get_if<Expression>(&piece); } const Markup& PatternPart::asMarkup() const { U_ASSERT(isMarkup()); return *std::get_if<Markup>(&piece); } // Precondition: isText(); const UnicodeString& PatternPart::asText() const { U_ASSERT(isText()); return *std::get_if<UnicodeString>(&piece); } PatternPart& PatternPart::operator=(PatternPart other) noexcept { swap(*this, other); return *this; } PatternPart::~PatternPart() {} // ---------------- Pattern Pattern::Pattern(const UVector& ps, UErrorCode& status) : len(ps.size()) { if (U_FAILURE(status)) { return; } PatternPart* result = copyVectorToArray<PatternPart>(ps, status); CHECK_ERROR(status); parts.adoptInstead(result); } // Copy constructor Pattern::Pattern(const Pattern& other) : len(other.len) { U_ASSERT(!other.bogus); UErrorCode localErrorCode = U_ZERO_ERROR; if (len == 0) { parts.adoptInstead(nullptr); } else { parts.adoptInstead(copyArray(other.parts.getAlias(), len, localErrorCode)); } if (U_FAILURE(localErrorCode)) { bogus = true; } } int32_t Pattern::numParts() const { U_ASSERT(!bogus); return len; } const PatternPart& Pattern::getPart(int32_t i) const { U_ASSERT(!bogus && i < numParts()); return parts[i]; } Pattern::Builder::Builder(UErrorCode& status) { parts = createUVector(status); } Pattern Pattern::Builder::build(UErrorCode& status) const noexcept { if (U_FAILURE(status)) { return {}; } U_ASSERT(parts != nullptr); return Pattern(*parts, status); } Pattern::Builder& Pattern::Builder::add(Expression&& part, UErrorCode& status) noexcept { U_ASSERT(parts != nullptr); if (U_SUCCESS(status)) { PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status); parts->adoptElement(l, status); } return *this; } Pattern::Builder& Pattern::Builder::add(Markup&& part, UErrorCode& status) noexcept { U_ASSERT(parts != nullptr); if (U_SUCCESS(status)) { PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status); parts->adoptElement(l, status); } return *this; } Pattern::Builder& Pattern::Builder::add(UnicodeString&& part, UErrorCode& status) noexcept { U_ASSERT(parts != nullptr); if (U_SUCCESS(status)) { PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status); parts->adoptElement(l, status); } return *this; } Pattern& Pattern::operator=(Pattern other) noexcept { swap(*this, other); return *this; } Pattern::Builder::~Builder() { if (parts != nullptr) { delete parts; } } Pattern::~Pattern() {} // ---------------- Binding const Expression& Binding::getValue() const { return expr; } /* static */ Binding Binding::input(UnicodeString&& variableName, Expression&& rhs, UErrorCode& errorCode) { Binding b; if (U_SUCCESS(errorCode)) { const Operand& rand = rhs.getOperand(); if (!(rand.isVariable() && (rand.asVariable() == variableName))) { errorCode = U_INVALID_STATE_ERROR; } else { const Operator* rator = rhs.getOperator(errorCode); bool hasOperator = U_SUCCESS(errorCode); // Clear error code -- the "error" from the absent operator // is handled errorCode = U_ZERO_ERROR; b = Binding(variableName, std::move(rhs)); b.local = false; if (hasOperator) { rator = b.getValue().getOperator(errorCode); U_ASSERT(U_SUCCESS(errorCode)); b.annotation = rator; } else { b.annotation = nullptr; } U_ASSERT(!hasOperator || b.annotation != nullptr); } } return b; } const OptionMap& Binding::getOptionsInternal() const { U_ASSERT(annotation != nullptr); return annotation->getOptionsInternal(); } void Binding::updateAnnotation() { UErrorCode localErrorCode = U_ZERO_ERROR; const Operator* rator = expr.getOperator(localErrorCode); if (U_FAILURE(localErrorCode)) { return; } U_ASSERT(U_SUCCESS(localErrorCode)); annotation = rator; } Binding::Binding(const Binding& other) : var(other.var), expr(other.expr), local(other.local) { updateAnnotation(); } Binding& Binding::operator=(Binding other) noexcept { swap(*this, other); return *this; } Binding::~Binding() {} // --------------- Variant Variant& Variant::operator=(Variant other) noexcept { swap(*this, other); return *this; } Variant::Variant(const Variant& other) : k(other.k), p(other.p) {} Variant::~Variant() {} // ------------- Matcher Matcher& Matcher::operator=(Matcher other) { swap(*this, other); return *this; } Matcher::Matcher(const Matcher& other) { U_ASSERT(!other.bogus); numSelectors = other.numSelectors; numVariants = other.numVariants; UErrorCode localErrorCode = U_ZERO_ERROR; selectors.adoptInstead(copyArray<VariableName>(other.selectors.getAlias(), numSelectors, localErrorCode)); variants.adoptInstead(copyArray<Variant>(other.variants.getAlias(), numVariants, localErrorCode)); if (U_FAILURE(localErrorCode)) { bogus = true; } } Matcher::Matcher(VariableName* ss, int32_t ns, Variant* vs, int32_t nv) : selectors(ss), numSelectors(ns), variants(vs), numVariants(nv) {} Matcher::~Matcher() {} // --------------- MFDataModel const Pattern& MFDataModel::getPattern() const { if (std::holds_alternative<Matcher>(body)) { // Return reference to empty pattern if this is a selectors message return empty; } return *(std::get_if<Pattern>(&body)); } // Returns nullptr if no bindings const Binding* MFDataModel::getLocalVariablesInternal() const { U_ASSERT(!bogus); U_ASSERT(bindingsLen == 0 || bindings.isValid()); return bindings.getAlias(); } const VariableName* MFDataModel::getSelectorsInternal() const { U_ASSERT(!bogus); U_ASSERT(!hasPattern()); return std::get_if<Matcher>(&body)->selectors.getAlias(); } const Variant* MFDataModel::getVariantsInternal() const { U_ASSERT(!bogus); U_ASSERT(!hasPattern()); return std::get_if<Matcher>(&body)->variants.getAlias(); } MFDataModel::Builder::Builder(UErrorCode& status) { bindings = createUVector(status); } // Invalidate pattern and create selectors/variants if necessary void MFDataModel::Builder::buildSelectorsMessage(UErrorCode& status) { CHECK_ERROR(status); if (hasPattern) { selectors = createUVector(status); variants = createUVector(status); hasPattern = false; } hasPattern = false; hasSelectors = true; } void MFDataModel::Builder::checkDuplicate(const VariableName& var, UErrorCode& status) const { CHECK_ERROR(status); // This means that handling declarations is quadratic in the number of variables, // but the `UVector` of locals in the builder could be changed to a `Hashtable` // if that's a problem // Note: this also doesn't check _all_ duplicate declaration errors, // see MessageFormatter::Checker::checkDeclarations() for (int32_t i = 0; i < bindings->size(); i++) { if ((static_cast<Binding*>(bindings->elementAt(i)))->getVariable() == var) { status = U_MF_DUPLICATE_DECLARATION_ERROR; break; } } } MFDataModel::Builder& MFDataModel::Builder::addBinding(Binding&& b, UErrorCode& status) { if (U_SUCCESS(status)) { U_ASSERT(bindings != nullptr); checkDuplicate(b.getVariable(), status); UErrorCode savedStatus = status; if (status == U_MF_DUPLICATE_DECLARATION_ERROR) { // Want to add the binding anyway even if it's a duplicate status = U_ZERO_ERROR; } bindings->adoptElement(create<Binding>(std::move(b), status), status); if (U_SUCCESS(status) || savedStatus == U_MF_DUPLICATE_DECLARATION_ERROR) { status = savedStatus; } } return *this; } MFDataModel::Builder& MFDataModel::Builder::addSelector(VariableName&& selector, UErrorCode& status) { THIS_ON_ERROR(status); buildSelectorsMessage(status); U_ASSERT(selectors != nullptr); selectors->adoptElement(create<VariableName>(std::move(selector), status), status); return *this; } /* `pattern` must be non-null */ MFDataModel::Builder& MFDataModel::Builder::addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept { buildSelectorsMessage(errorCode); Variant* v = create<Variant>(Variant(std::move(keys), std::move(pattern)), errorCode); if (U_SUCCESS(errorCode)) { variants->adoptElement(v, errorCode); } return *this; } MFDataModel::Builder& MFDataModel::Builder::setPattern(Pattern&& pat) { pattern = std::move(pat); hasPattern = true; hasSelectors = false; // Invalidate variants if (variants != nullptr) { variants->removeAllElements(); } return *this; } MFDataModel::MFDataModel(const MFDataModel& other) : body(Pattern()) { U_ASSERT(!other.bogus); UErrorCode localErrorCode = U_ZERO_ERROR; if (other.hasPattern()) { body = *std::get_if<Pattern>(&other.body); } else { const VariableName* otherSelectors = other.getSelectorsInternal(); const Variant* otherVariants = other.getVariantsInternal(); int32_t numSelectors = other.numSelectors(); int32_t numVariants = other.numVariants(); LocalArray<VariableName> copiedSelectors(copyArray(otherSelectors, numSelectors, localErrorCode), localErrorCode); LocalArray<Variant> copiedVariants(copyArray(otherVariants, numVariants, localErrorCode), localErrorCode); if (U_FAILURE(localErrorCode)) { bogus = true; return; } body = Matcher(copiedSelectors.orphan(), numSelectors, copiedVariants.orphan(), numVariants); } bindingsLen = other.bindingsLen; if (bindingsLen > 0) { bindings.adoptInstead(copyArray(other.bindings.getAlias(), bindingsLen, localErrorCode)); } if (U_FAILURE(localErrorCode)) { bogus = true; } } MFDataModel::MFDataModel(const MFDataModel::Builder& builder, UErrorCode& errorCode) noexcept : body(Pattern()) { CHECK_ERROR(errorCode); if (builder.hasPattern) { body.emplace<Pattern>(builder.pattern); } else { U_ASSERT(builder.variants != nullptr); U_ASSERT(builder.selectors != nullptr); int32_t numVariants = builder.variants->size(); int32_t numSelectors = builder.selectors->size(); LocalArray<Variant> variants(copyVectorToArray<Variant>(*builder.variants, errorCode), errorCode); LocalArray<VariableName> selectors(copyVectorToArray<VariableName>(*builder.selectors, errorCode), errorCode); if (U_FAILURE(errorCode)) { bogus = true; return; } body.emplace<Matcher>(Matcher(selectors.orphan(), numSelectors, variants.orphan(), numVariants)); } U_ASSERT(builder.bindings != nullptr); bindingsLen = builder.bindings->size(); if (bindingsLen > 0) { bindings.adoptInstead(copyVectorToArray<Binding>(*builder.bindings, errorCode)); } if (U_FAILURE(errorCode)) { bogus = true; } } MFDataModel::MFDataModel() : body(Pattern()) {} MFDataModel& MFDataModel::operator=(MFDataModel other) noexcept { U_ASSERT(!other.bogus); swap(*this, other); return *this; } MFDataModel MFDataModel::Builder::build(UErrorCode& errorCode) const noexcept { if (U_FAILURE(errorCode)) { return {}; } if (!hasPattern && !hasSelectors) { errorCode = U_INVALID_STATE_ERROR; } return MFDataModel(*this, errorCode); } MFDataModel::~MFDataModel() {} MFDataModel::Builder::~Builder() { if (selectors != nullptr) { delete selectors; } if (variants != nullptr) { delete variants; } if (bindings != nullptr) { delete bindings; } } } // namespace data_model } // namespace message2 U_NAMESPACE_END #endif /* #if !UCONFIG_NO_MF2 */ #endif /* #if !UCONFIG_NO_FORMATTING */ #endif /* #if !UCONFIG_NO_NORMALIZATION */