// © 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_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(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(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(*contents)); } UBool Operand::isLiteral() const { return (contents.has_value() && std::holds_alternative(*contents)); } UBool Operand::isNull() const { return !contents.has_value(); } const Literal& Operand::asLiteral() const { U_ASSERT(isLiteral()); return *(std::get_if(&(*contents))); } const VariableName& Operand::asVariable() const { U_ASSERT(isVariable()); return *(std::get_if(&(*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(); } return (asLiteral() == other.asLiteral()); } const Literal& Key::asLiteral() const { U_ASSERT(!isWildcard()); return *contents; } Key::~Key() {} // ------------ Reserved // Copy constructor Reserved::Reserved(const Reserved& 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; } } Reserved& Reserved::operator=(Reserved other) noexcept { swap(*this, other); return *this; } Reserved::Reserved(const UVector& ps, UErrorCode& status) noexcept : len(ps.size()) { if (U_FAILURE(status)) { return; } parts = LocalArray(copyVectorToArray(ps, status)); } int32_t Reserved::numParts() const { U_ASSERT(!bogus); return len; } const Literal& Reserved::getPart(int32_t i) const { U_ASSERT(!bogus); U_ASSERT(i < numParts()); return parts[i]; } Reserved::Builder::Builder(UErrorCode& status) { parts = createUVector(status); } Reserved Reserved::Builder::build(UErrorCode& status) const noexcept { if (U_FAILURE(status)) { return {}; } U_ASSERT(parts != nullptr); return Reserved(*parts, status); } Reserved::Builder& Reserved::Builder::add(Literal&& part, UErrorCode& status) noexcept { U_ASSERT(parts != nullptr); if (U_SUCCESS(status)) { Literal* l = create(std::move(part), status); parts->adoptElement(l, status); } return *this; } Reserved::Builder::~Builder() { if (parts != nullptr) { delete parts; } } Reserved::~Reserved() { len = 0; } //------------------------ Operator OptionMap::OptionMap(const UVector& opts, UErrorCode& status) : len(opts.size()) { Option* result = copyVectorToArray