node/deps/icu-small/source/i18n/messageformat2_data_model.cpp
Node.js GitHub Bot ab9660b55a
Some checks failed
Coverage Linux (without intl) / coverage-linux-without-intl (push) Waiting to run
Coverage Linux / coverage-linux (push) Waiting to run
Coverage Windows / coverage-windows (push) Waiting to run
Test and upload documentation to artifacts / build-docs (push) Waiting to run
Linters / lint-addon-docs (push) Waiting to run
Linters / lint-cpp (push) Waiting to run
Linters / format-cpp (push) Waiting to run
Linters / lint-js-and-md (push) Waiting to run
Linters / lint-py (push) Waiting to run
Linters / lint-yaml (push) Waiting to run
Linters / lint-sh (push) Waiting to run
Linters / lint-codeowners (push) Waiting to run
Linters / lint-pr-url (push) Waiting to run
Linters / lint-readme (push) Waiting to run
Notify on Push / Notify on Force Push on `main` (push) Waiting to run
Notify on Push / Notify on Push on `main` that lacks metadata (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
License update / update_license (push) Has been cancelled
Find inactive collaborators / find (push) Has been cancelled
deps: update icu to 77.1
PR-URL: https://github.com/nodejs/node/pull/57455
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Steven R Loomis <srl295@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
2025-03-16 20:10:32 +00:00

925 lines
25 KiB
C++

// © 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 {
// 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();
VariableName* copiedSelectors = copyArray(otherSelectors, numSelectors, localErrorCode);
Variant* copiedVariants = copyArray(otherVariants, numVariants, localErrorCode);
if (U_FAILURE(localErrorCode)) {
bogus = true;
return;
}
body = Matcher(copiedSelectors, numSelectors, copiedVariants, 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 message2
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_MF2 */
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif /* #if !UCONFIG_NO_NORMALIZATION */