// © 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 */
