• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2024 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 #if !UCONFIG_NO_MF2
9 
10 #include "unicode/messageformat2_data_model.h"
11 #include "messageformat2_allocation.h"
12 #include "messageformat2_macros.h"
13 #include "uvector.h"
14 
15 U_NAMESPACE_BEGIN
16 
17 namespace message2 {
18 
19 // Implementation
20 
21 //------------------ SelectorKeys
22 
getKeysInternal() const23 const Key* SelectorKeys::getKeysInternal() const {
24     return keys.getAlias();
25 }
26 
27 // Lexically order key lists
operator <(const SelectorKeys & other) const28 bool SelectorKeys::operator<(const SelectorKeys& other) const {
29     // Handle key lists of different sizes first --
30     // this case does have to be handled (even though it would
31     // reflect a data model error) because of the need to produce
32     // partial output
33     if (len < other.len) {
34         return true;
35     }
36     if (len > other.len) {
37         return false;
38     }
39 
40     for (int32_t i = 0; i < len; i++) {
41         if (keys[i] < other.keys[i]) {
42             return true;
43         }
44         if (!(keys[i] == other.keys[i])) {
45             return false;
46         }
47     }
48     // If we've reached here, all keys must be equal
49     return false;
50 }
51 
Builder(UErrorCode & status)52 SelectorKeys::Builder::Builder(UErrorCode& status) {
53     keys = createUVector(status);
54 }
55 
add(Key && key,UErrorCode & status)56 SelectorKeys::Builder& SelectorKeys::Builder::add(Key&& key, UErrorCode& status) noexcept {
57     U_ASSERT(keys != nullptr);
58     if (U_SUCCESS(status)) {
59         Key* k = create<Key>(std::move(key), status);
60         keys->adoptElement(k, status);
61     }
62     return *this;
63 }
64 
build(UErrorCode & status) const65 SelectorKeys SelectorKeys::Builder::build(UErrorCode& status) const {
66     if (U_FAILURE(status)) {
67         return {};
68     }
69     U_ASSERT(keys != nullptr);
70     return SelectorKeys(*keys, status);
71 }
72 
~Builder()73 SelectorKeys::Builder::~Builder() {
74     if (keys != nullptr) {
75         delete keys;
76     }
77 }
78 
SelectorKeys(const UVector & ks,UErrorCode & status)79 SelectorKeys::SelectorKeys(const UVector& ks, UErrorCode& status) : len(ks.size()) {
80     Key* result = copyVectorToArray<Key>(ks, status);
81     if (U_FAILURE(status)) {
82         return;
83     }
84     keys.adoptInstead(result);
85 }
86 
operator =(SelectorKeys other)87 SelectorKeys& SelectorKeys::operator=(SelectorKeys other) noexcept {
88     swap(*this, other);
89     return *this;
90 }
91 
SelectorKeys(const SelectorKeys & other)92 SelectorKeys::SelectorKeys(const SelectorKeys& other) : len(other.len) {
93     UErrorCode localErrorCode = U_ZERO_ERROR;
94     if (len != 0) {
95         keys.adoptInstead(copyArray(other.keys.getAlias(), len, localErrorCode));
96     }
97     if (U_FAILURE(localErrorCode)) {
98         len = 0;
99     }
100 }
101 
~SelectorKeys()102 SelectorKeys::~SelectorKeys() {
103     len = 0;
104 }
105 
106 //------------------ Literal
107 
operator <(const Literal & other) const108 bool Literal::operator<(const Literal& other) const {
109     // Ignore quoting for the purposes of ordering
110     return contents < other.contents;
111 }
112 
operator ==(const Literal & other) const113 bool Literal::operator==(const Literal& other) const {
114     // Ignore quoting for the purposes of ordering
115     return contents == other.contents;
116 }
117 
quoted() const118 UnicodeString Literal::quoted() const {
119     UnicodeString result(PIPE);
120     result += unquoted();
121     result += PIPE;
122     return result;
123 }
124 
unquoted() const125 const UnicodeString& Literal::unquoted() const { return contents; }
126 
operator =(Literal other)127 Literal& Literal::operator=(Literal other) noexcept {
128     swap(*this, other);
129 
130     return *this;
131 }
132 
~Literal()133 Literal::~Literal() {
134     thisIsQuoted = false;
135 }
136 
137 //------------------ Operand
138 
Operand(const Operand & other)139 Operand::Operand(const Operand& other) : contents(other.contents) {}
140 
operator =(Operand other)141 Operand& Operand::operator=(Operand other) noexcept {
142     swap(*this, other);
143 
144     return *this;
145 }
146 
isVariable() const147 UBool Operand::isVariable() const {
148     return (contents.has_value() && std::holds_alternative<VariableName>(*contents));
149 }
isLiteral() const150 UBool Operand::isLiteral() const {
151     return (contents.has_value() && std::holds_alternative<Literal>(*contents));
152 }
isNull() const153 UBool Operand::isNull() const { return !contents.has_value(); }
154 
asLiteral() const155 const Literal& Operand::asLiteral() const {
156     U_ASSERT(isLiteral());
157     return *(std::get_if<Literal>(&(*contents)));
158 }
159 
asVariable() const160 const VariableName& Operand::asVariable() const {
161     U_ASSERT(isVariable());
162     return *(std::get_if<VariableName>(&(*contents)));
163 }
164 
~Operand()165 Operand::~Operand() {}
166 
167 //---------------- Key
168 
operator =(Key other)169 Key& Key::operator=(Key other) noexcept {
170     swap(*this, other);
171     return *this;
172 }
173 
operator <(const Key & other) const174 bool Key::operator<(const Key& other) const {
175     // Arbitrarily treat * as greater than all concrete keys
176     if (isWildcard()) {
177         return false;
178     }
179     if (other.isWildcard()) {
180         return true;
181     }
182     return (asLiteral() < other.asLiteral());
183 }
184 
operator ==(const Key & other) const185 bool Key::operator==(const Key& other) const {
186     if (isWildcard()) {
187         return other.isWildcard();
188     }
189     if (other.isWildcard()) {
190         return false;
191     }
192     return (asLiteral() == other.asLiteral());
193 }
194 
asLiteral() const195 const Literal& Key::asLiteral() const {
196     U_ASSERT(!isWildcard());
197     return *contents;
198 }
199 
~Key()200 Key::~Key() {}
201 
202 //------------------------ Operator
203 
OptionMap(const UVector & opts,UErrorCode & status)204 OptionMap::OptionMap(const UVector& opts, UErrorCode& status) : len(opts.size()) {
205     Option* result = copyVectorToArray<Option>(opts, status);
206     if (U_FAILURE(status)) {
207         bogus = true;
208         return;
209     }
210     options.adoptInstead(result);
211     bogus = false;
212 }
213 
OptionMap(const OptionMap & other)214 OptionMap::OptionMap(const OptionMap& other) : len(other.len) {
215     U_ASSERT(!other.bogus);
216     if (len == 0) {
217         bogus = false;
218         return;
219     }
220     UErrorCode localErrorCode = U_ZERO_ERROR;
221     Option* result = copyArray(other.options.getAlias(), len, localErrorCode);
222     if (U_FAILURE(localErrorCode)) {
223         bogus = true;
224         return;
225     }
226     bogus = false;
227     options.adoptInstead(result);
228 }
229 
operator =(OptionMap other)230 OptionMap& OptionMap::operator=(OptionMap other) {
231     swap(*this, other);
232     return *this;
233 }
234 
getOption(int32_t i,UErrorCode & status) const235 const Option& OptionMap::getOption(int32_t i, UErrorCode& status) const {
236     if (U_FAILURE(status) || bogus) {
237         if (bogus) {
238             status = U_MEMORY_ALLOCATION_ERROR;
239         }
240     } else {
241         U_ASSERT(options.isValid());
242         U_ASSERT(i < len);
243     }
244     return options[i];
245 }
246 
size() const247 int32_t OptionMap::size() const {
248     U_ASSERT(options.isValid() || len == 0);
249     return len;
250 }
251 
~OptionMap()252 OptionMap::~OptionMap() {}
253 
build(UErrorCode & status)254 OptionMap OptionMap::Builder::build(UErrorCode& status) {
255     return OptionMap(*options, status);
256 }
257 
Builder(UErrorCode & status)258 OptionMap::Builder::Builder(UErrorCode& status) {
259     options = createStringUVector(status);
260 }
261 
Builder(OptionMap::Builder && other)262 OptionMap::Builder::Builder(OptionMap::Builder&& other) {
263     checkDuplicates = other.checkDuplicates;
264     options = other.options;
265     other.options = nullptr;
266 }
267 
operator =(OptionMap::Builder other)268 OptionMap::Builder& OptionMap::Builder::operator=(OptionMap::Builder other) noexcept {
269     swap(*this, other);
270     return *this;
271 }
272 
attributes(UErrorCode & status)273 /* static */ OptionMap::Builder OptionMap::Builder::attributes(UErrorCode& status) {
274     Builder b(status);
275     // The same code is re-used for representing attributes and options.
276     // Duplicate attributes are allowed, while duplicate options are disallowed.
277     b.checkDuplicates = false;
278     return b;
279 }
280 
hasOptionNamed(const UVector & v,const UnicodeString & s)281 static UBool hasOptionNamed(const UVector& v, const UnicodeString& s) {
282     for (int32_t i = 0; i < v.size(); i++) {
283         const Option* opt = static_cast<Option*>(v[i]);
284         U_ASSERT(opt != nullptr);
285         if (opt->getName() == s) {
286             return true;
287         }
288     }
289     return false;
290 }
291 
add(Option && opt,UErrorCode & status)292 OptionMap::Builder& OptionMap::Builder::add(Option&& opt, UErrorCode& status) {
293     THIS_ON_ERROR(status);
294 
295     // If the option name is already in the map, emit a data model error
296     if (checkDuplicates && hasOptionNamed(*options, opt.getName())) {
297         status = U_MF_DUPLICATE_OPTION_NAME_ERROR;
298     } else {
299         Option* newOption = create<Option>(std::move(opt), status);
300         options->adoptElement(newOption, status);
301     }
302     return *this;
303 }
304 
~Builder()305 OptionMap::Builder::~Builder() {
306     if (options != nullptr) {
307         delete options;
308     }
309 }
310 
getOptionsInternal() const311 const OptionMap& Operator::getOptionsInternal() const {
312     return options;
313 }
314 
Option(const Option & other)315 Option::Option(const Option& other): name(other.name), rand(other.rand) {}
316 
operator =(Option other)317 Option& Option::operator=(Option other) noexcept {
318     swap(*this, other);
319     return *this;
320 }
321 
~Option()322 Option::~Option() {}
323 
Builder(UErrorCode & status)324 Operator::Builder::Builder(UErrorCode& status) : options(OptionMap::Builder(status)) {}
325 
setFunctionName(FunctionName && func)326 Operator::Builder& Operator::Builder::setFunctionName(FunctionName&& func) {
327     functionName = std::move(func);
328     return *this;
329 }
330 
getFunctionName() const331 const FunctionName& Operator::getFunctionName() const {
332     return name;
333 }
334 
addOption(const UnicodeString & key,Operand && value,UErrorCode & errorCode)335 Operator::Builder& Operator::Builder::addOption(const UnicodeString &key, Operand&& value, UErrorCode& errorCode) noexcept {
336     THIS_ON_ERROR(errorCode);
337 
338     options.add(Option(key, std::move(value)), errorCode);
339     return *this;
340 }
341 
build(UErrorCode & errorCode)342 Operator Operator::Builder::build(UErrorCode& errorCode) {
343     return Operator(functionName, options.build(errorCode));
344 }
345 
Operator(const Operator & other)346 Operator::Operator(const Operator& other) noexcept
347     : name(other.name), options(other.options) {}
348 
operator =(Operator other)349 Operator& Operator::operator=(Operator other) noexcept {
350     swap(*this, other);
351     return *this;
352 }
353 
354 // Function call
355 
Operator(const FunctionName & f,const OptionMap & opts)356 Operator::Operator(const FunctionName& f, const OptionMap& opts) : name(f), options(opts) {}
357 
~Builder()358 Operator::Builder::~Builder() {}
359 
~Operator()360 Operator::~Operator() {}
361 
362 // ------------ Markup
363 
Builder(UErrorCode & status)364 Markup::Builder::Builder(UErrorCode& status)
365     : options(OptionMap::Builder(status)), attributes(OptionMap::Builder::attributes(status)) {}
366 
Markup(UMarkupType ty,UnicodeString n,OptionMap && o,OptionMap && a)367 Markup::Markup(UMarkupType ty, UnicodeString n, OptionMap&& o, OptionMap&& a)
368     : type(ty), name(n), options(std::move(o)), attributes(std::move(a)) {}
369 
addOption(const UnicodeString & key,Operand && value,UErrorCode & errorCode)370 Markup::Builder& Markup::Builder::addOption(const UnicodeString &key,
371                                             Operand&& value,
372                                             UErrorCode& errorCode) {
373     options.add(Option(key, std::move(value)), errorCode);
374     return *this;
375 }
376 
addAttribute(const UnicodeString & key,Operand && value,UErrorCode & errorCode)377 Markup::Builder& Markup::Builder::addAttribute(const UnicodeString &key,
378                                                Operand&& value,
379                                                UErrorCode& errorCode) {
380     attributes.add(Option(key, std::move(value)), errorCode);
381     return *this;
382 }
383 
build(UErrorCode & errorCode)384 Markup Markup::Builder::build(UErrorCode& errorCode) {
385     Markup result;
386 
387     if (U_FAILURE(errorCode)) {
388         return result;
389     }
390 
391     if (type == UMARKUP_COUNT || name.length() == 0) {
392         // One of `setOpen()`, `setClose()`, or `setStandalone()`
393         // must be called before calling build()
394         // setName() must be called before calling build()
395         errorCode = U_INVALID_STATE_ERROR;
396     } else {
397         result = Markup(type,
398                         name,
399                         options.build(errorCode),
400                         attributes.build(errorCode));
401     }
402     return result;
403 }
404 
~Builder()405 Markup::Builder::~Builder() {}
406 
~Markup()407 Markup::~Markup() {}
408 
409 // ------------ Expression
410 
Builder(UErrorCode & status)411 Expression::Builder::Builder(UErrorCode& status)
412     : attributes(OptionMap::Builder::attributes(status)) {}
413 
isStandaloneAnnotation() const414 UBool Expression::isStandaloneAnnotation() const {
415     return rand.isNull();
416 }
417 
418 // Returns true for function calls with operands as well as
419 // standalone annotations.
isFunctionCall() const420 UBool Expression::isFunctionCall() const {
421     return rator.has_value();
422 }
423 
getOperator(UErrorCode & status) const424 const Operator* Expression::getOperator(UErrorCode& status) const {
425     NULL_ON_ERROR(status);
426 
427     if (!isFunctionCall()) {
428         status = U_INVALID_STATE_ERROR;
429         return nullptr;
430     }
431     U_ASSERT(rator);
432     return &(*rator);
433 }
434 
435 // May return null operand
getOperand() const436 const Operand& Expression::getOperand() const { return rand; }
437 
setOperand(Operand && rAnd)438 Expression::Builder& Expression::Builder::setOperand(Operand&& rAnd) {
439     hasOperand = true;
440     rand = std::move(rAnd);
441     return *this;
442 }
443 
setOperator(Operator && rAtor)444 Expression::Builder& Expression::Builder::setOperator(Operator&& rAtor) {
445     hasOperator = true;
446     rator = std::move(rAtor);
447     return *this;
448 }
449 
addAttribute(const UnicodeString & k,Operand && v,UErrorCode & status)450 Expression::Builder& Expression::Builder::addAttribute(const UnicodeString& k,
451                                                        Operand&& v,
452                                                        UErrorCode& status) {
453     attributes.add(Option(k, std::move(v)), status);
454     return *this;
455 }
456 
build(UErrorCode & errorCode)457 Expression Expression::Builder::build(UErrorCode& errorCode) {
458     Expression result;
459 
460     if (U_FAILURE(errorCode)) {
461         return result;
462     }
463 
464     if ((!hasOperand || rand.isNull()) && !hasOperator) {
465         errorCode = U_INVALID_STATE_ERROR;
466         return result;
467     }
468 
469     OptionMap attributeMap = attributes.build(errorCode);
470     if (hasOperand && hasOperator) {
471         result = Expression(rator, rand, std::move(attributeMap));
472     } else if (hasOperand && !hasOperator) {
473         result = Expression(rand, std::move(attributeMap));
474     } else {
475         // rator is valid, rand is not valid
476         result = Expression(rator, std::move(attributeMap));
477     }
478     return result;
479 }
480 
Expression()481 Expression::Expression() : rator(std::nullopt) {}
482 
Expression(const Expression & other)483 Expression::Expression(const Expression& other) : rator(other.rator), rand(other.rand), attributes(other.attributes) {}
484 
operator =(Expression other)485 Expression& Expression::operator=(Expression other) noexcept {
486     swap(*this, other);
487     return *this;
488 }
489 
~Builder()490 Expression::Builder::~Builder() {}
491 
~Expression()492 Expression::~Expression() {}
493 
494 // ----------- PatternPart
495 
496 // PatternPart needs a copy constructor in order to make Pattern deeply copyable
497 // If !isRawText and the copy of the other expression fails,
498 // then isBogus() will be true for this PatternPart
PatternPart(const PatternPart & other)499 PatternPart::PatternPart(const PatternPart& other) : piece(other.piece) {}
500 
contents() const501 const Expression& PatternPart::contents() const {
502     U_ASSERT(isExpression());
503     return *std::get_if<Expression>(&piece);
504 }
505 
asMarkup() const506 const Markup& PatternPart::asMarkup() const {
507     U_ASSERT(isMarkup());
508     return *std::get_if<Markup>(&piece);
509 }
510 
511 // Precondition: isText();
asText() const512 const UnicodeString& PatternPart::asText() const {
513     U_ASSERT(isText());
514     return *std::get_if<UnicodeString>(&piece);
515 }
516 
operator =(PatternPart other)517 PatternPart& PatternPart::operator=(PatternPart other) noexcept {
518     swap(*this, other);
519     return *this;
520 }
521 
~PatternPart()522 PatternPart::~PatternPart() {}
523 
524 // ---------------- Pattern
525 
Pattern(const UVector & ps,UErrorCode & status)526 Pattern::Pattern(const UVector& ps, UErrorCode& status) : len(ps.size()) {
527     if (U_FAILURE(status)) {
528         return;
529     }
530     PatternPart* result = copyVectorToArray<PatternPart>(ps, status);
531     CHECK_ERROR(status);
532     parts.adoptInstead(result);
533 }
534 
535 // Copy constructor
Pattern(const Pattern & other)536 Pattern::Pattern(const Pattern& other) : len(other.len) {
537     U_ASSERT(!other.bogus);
538     UErrorCode localErrorCode = U_ZERO_ERROR;
539     if (len == 0) {
540         parts.adoptInstead(nullptr);
541     } else {
542         parts.adoptInstead(copyArray(other.parts.getAlias(), len, localErrorCode));
543     }
544     if (U_FAILURE(localErrorCode)) {
545         bogus = true;
546     }
547 }
548 
numParts() const549 int32_t Pattern::numParts() const {
550     U_ASSERT(!bogus);
551     return len;
552 }
553 
getPart(int32_t i) const554 const PatternPart& Pattern::getPart(int32_t i) const {
555     U_ASSERT(!bogus && i < numParts());
556     return parts[i];
557 }
558 
Builder(UErrorCode & status)559 Pattern::Builder::Builder(UErrorCode& status) {
560     parts = createUVector(status);
561 }
562 
build(UErrorCode & status) const563 Pattern Pattern::Builder::build(UErrorCode& status) const noexcept {
564     if (U_FAILURE(status)) {
565         return {};
566     }
567     U_ASSERT(parts != nullptr);
568     return Pattern(*parts, status);
569 }
570 
add(Expression && part,UErrorCode & status)571 Pattern::Builder& Pattern::Builder::add(Expression&& part, UErrorCode& status) noexcept {
572     U_ASSERT(parts != nullptr);
573     if (U_SUCCESS(status)) {
574         PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status);
575         parts->adoptElement(l, status);
576     }
577     return *this;
578 }
579 
add(Markup && part,UErrorCode & status)580 Pattern::Builder& Pattern::Builder::add(Markup&& part, UErrorCode& status) noexcept {
581     U_ASSERT(parts != nullptr);
582     if (U_SUCCESS(status)) {
583         PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status);
584         parts->adoptElement(l, status);
585     }
586     return *this;
587 }
588 
add(UnicodeString && part,UErrorCode & status)589 Pattern::Builder& Pattern::Builder::add(UnicodeString&& part, UErrorCode& status) noexcept {
590     U_ASSERT(parts != nullptr);
591     if (U_SUCCESS(status)) {
592         PatternPart* l = create<PatternPart>(PatternPart(std::move(part)), status);
593         parts->adoptElement(l, status);
594     }
595     return *this;
596 }
597 
operator =(Pattern other)598 Pattern& Pattern::operator=(Pattern other) noexcept {
599     swap(*this, other);
600 
601     return *this;
602 }
603 
~Builder()604 Pattern::Builder::~Builder() {
605     if (parts != nullptr) {
606         delete parts;
607     }
608 }
609 
~Pattern()610 Pattern::~Pattern() {}
611 
612 // ---------------- Binding
613 
getValue() const614 const Expression& Binding::getValue() const {
615     return expr;
616 }
617 
input(UnicodeString && variableName,Expression && rhs,UErrorCode & errorCode)618 /* static */ Binding Binding::input(UnicodeString&& variableName, Expression&& rhs, UErrorCode& errorCode) {
619     Binding b;
620     if (U_SUCCESS(errorCode)) {
621         const Operand& rand = rhs.getOperand();
622         if (!(rand.isVariable() && (rand.asVariable() == variableName))) {
623             errorCode = U_INVALID_STATE_ERROR;
624         } else {
625             const Operator* rator = rhs.getOperator(errorCode);
626             bool hasOperator = U_SUCCESS(errorCode);
627             // Clear error code -- the "error" from the absent operator
628             // is handled
629             errorCode = U_ZERO_ERROR;
630             b = Binding(variableName, std::move(rhs));
631             b.local = false;
632             if (hasOperator) {
633                 rator = b.getValue().getOperator(errorCode);
634                 U_ASSERT(U_SUCCESS(errorCode));
635                 b.annotation = rator;
636             } else {
637                 b.annotation = nullptr;
638             }
639             U_ASSERT(!hasOperator || b.annotation != nullptr);
640         }
641     }
642     return b;
643 }
644 
getOptionsInternal() const645 const OptionMap& Binding::getOptionsInternal() const {
646     U_ASSERT(annotation != nullptr);
647     return annotation->getOptionsInternal();
648 }
649 
updateAnnotation()650 void Binding::updateAnnotation() {
651     UErrorCode localErrorCode = U_ZERO_ERROR;
652     const Operator* rator = expr.getOperator(localErrorCode);
653     if (U_FAILURE(localErrorCode)) {
654         return;
655     }
656     U_ASSERT(U_SUCCESS(localErrorCode));
657     annotation = rator;
658 }
659 
Binding(const Binding & other)660 Binding::Binding(const Binding& other) : var(other.var), expr(other.expr), local(other.local) {
661     updateAnnotation();
662 }
663 
operator =(Binding other)664 Binding& Binding::operator=(Binding other) noexcept {
665     swap(*this, other);
666     return *this;
667 }
668 
~Binding()669 Binding::~Binding() {}
670 
671 // --------------- Variant
672 
operator =(Variant other)673 Variant& Variant::operator=(Variant other) noexcept {
674     swap(*this, other);
675     return *this;
676 }
677 
Variant(const Variant & other)678 Variant::Variant(const Variant& other) : k(other.k), p(other.p) {}
679 
~Variant()680 Variant::~Variant() {}
681 
682 // ------------- Matcher
683 
operator =(Matcher other)684 Matcher& Matcher::operator=(Matcher other) {
685     swap(*this, other);
686     return *this;
687 }
688 
Matcher(const Matcher & other)689 Matcher::Matcher(const Matcher& other) {
690     U_ASSERT(!other.bogus);
691     numSelectors = other.numSelectors;
692     numVariants = other.numVariants;
693     UErrorCode localErrorCode = U_ZERO_ERROR;
694     selectors.adoptInstead(copyArray<Expression>(other.selectors.getAlias(),
695                                                  numSelectors,
696                                                  localErrorCode));
697     variants.adoptInstead(copyArray<Variant>(other.variants.getAlias(),
698                                              numVariants,
699                                              localErrorCode));
700     if (U_FAILURE(localErrorCode)) {
701         bogus = true;
702     }
703 }
704 
Matcher(Expression * ss,int32_t ns,Variant * vs,int32_t nv)705 Matcher::Matcher(Expression* ss, int32_t ns, Variant* vs, int32_t nv)
706     : selectors(ss), numSelectors(ns), variants(vs), numVariants(nv) {}
707 
~Matcher()708 Matcher::~Matcher() {}
709 
710 // --------------- MFDataModel
711 
getPattern() const712 const Pattern& MFDataModel::getPattern() const {
713     if (std::holds_alternative<Matcher>(body)) {
714         // Return reference to empty pattern if this is a selectors message
715         return empty;
716     }
717     return *(std::get_if<Pattern>(&body));
718 }
719 
720 // Returns nullptr if no bindings
getLocalVariablesInternal() const721 const Binding* MFDataModel::getLocalVariablesInternal() const {
722     U_ASSERT(!bogus);
723     U_ASSERT(bindingsLen == 0 || bindings.isValid());
724     return bindings.getAlias();
725 }
726 
getSelectorsInternal() const727 const Expression* MFDataModel::getSelectorsInternal() const {
728     U_ASSERT(!bogus);
729     U_ASSERT(!hasPattern());
730     return std::get_if<Matcher>(&body)->selectors.getAlias();
731 }
732 
getVariantsInternal() const733 const Variant* MFDataModel::getVariantsInternal() const {
734     U_ASSERT(!bogus);
735     U_ASSERT(!hasPattern());
736     return std::get_if<Matcher>(&body)->variants.getAlias();
737 }
738 
Builder(UErrorCode & status)739 MFDataModel::Builder::Builder(UErrorCode& status) {
740     bindings = createUVector(status);
741 }
742 
743 // Invalidate pattern and create selectors/variants if necessary
buildSelectorsMessage(UErrorCode & status)744 void MFDataModel::Builder::buildSelectorsMessage(UErrorCode& status) {
745     CHECK_ERROR(status);
746 
747     if (hasPattern) {
748         selectors = createUVector(status);
749         variants = createUVector(status);
750         hasPattern = false;
751     }
752     hasPattern = false;
753     hasSelectors = true;
754 }
755 
checkDuplicate(const VariableName & var,UErrorCode & status) const756 void MFDataModel::Builder::checkDuplicate(const VariableName& var, UErrorCode& status) const {
757     CHECK_ERROR(status);
758 
759     // This means that handling declarations is quadratic in the number of variables,
760     // but the `UVector` of locals in the builder could be changed to a `Hashtable`
761     // if that's a problem
762     // Note: this also doesn't check _all_ duplicate declaration errors,
763     // see MessageFormatter::Checker::checkDeclarations()
764     for (int32_t i = 0; i < bindings->size(); i++) {
765         if ((static_cast<Binding*>(bindings->elementAt(i)))->getVariable() == var) {
766             status = U_MF_DUPLICATE_DECLARATION_ERROR;
767             break;
768         }
769     }
770 }
771 
addBinding(Binding && b,UErrorCode & status)772 MFDataModel::Builder& MFDataModel::Builder::addBinding(Binding&& b, UErrorCode& status) {
773     if (U_SUCCESS(status)) {
774         U_ASSERT(bindings != nullptr);
775         checkDuplicate(b.getVariable(), status);
776         UErrorCode savedStatus = status;
777         if (status == U_MF_DUPLICATE_DECLARATION_ERROR) {
778             // Want to add the binding anyway even if it's a duplicate
779             status = U_ZERO_ERROR;
780         }
781         bindings->adoptElement(create<Binding>(std::move(b), status), status);
782         if (U_SUCCESS(status) || savedStatus == U_MF_DUPLICATE_DECLARATION_ERROR) {
783             status = savedStatus;
784         }
785     }
786     return *this;
787 }
788 
789 /*
790   selector must be non-null
791 */
addSelector(Expression && selector,UErrorCode & status)792 MFDataModel::Builder& MFDataModel::Builder::addSelector(Expression&& selector, UErrorCode& status) noexcept {
793     THIS_ON_ERROR(status);
794 
795     buildSelectorsMessage(status);
796     U_ASSERT(selectors != nullptr);
797     selectors->adoptElement(create<Expression>(std::move(selector), status), status);
798 
799     return *this;
800 }
801 
802 /*
803   `pattern` must be non-null
804 */
addVariant(SelectorKeys && keys,Pattern && pattern,UErrorCode & errorCode)805 MFDataModel::Builder& MFDataModel::Builder::addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept {
806     buildSelectorsMessage(errorCode);
807     Variant* v = create<Variant>(Variant(std::move(keys), std::move(pattern)), errorCode);
808     if (U_SUCCESS(errorCode)) {
809         variants->adoptElement(v, errorCode);
810     }
811     return *this;
812 }
813 
setPattern(Pattern && pat)814 MFDataModel::Builder& MFDataModel::Builder::setPattern(Pattern&& pat) {
815     pattern = std::move(pat);
816     hasPattern = true;
817     hasSelectors = false;
818     // Invalidate variants
819     if (variants != nullptr) {
820         variants->removeAllElements();
821     }
822     return *this;
823 }
824 
MFDataModel(const MFDataModel & other)825 MFDataModel::MFDataModel(const MFDataModel& other) : body(Pattern()) {
826     U_ASSERT(!other.bogus);
827 
828     UErrorCode localErrorCode = U_ZERO_ERROR;
829 
830     if (other.hasPattern()) {
831         body = *std::get_if<Pattern>(&other.body);
832     } else {
833         const Expression* otherSelectors = other.getSelectorsInternal();
834         const Variant* otherVariants = other.getVariantsInternal();
835         int32_t numSelectors = other.numSelectors();
836         int32_t numVariants = other.numVariants();
837         Expression* copiedSelectors = copyArray(otherSelectors, numSelectors, localErrorCode);
838         Variant* copiedVariants = copyArray(otherVariants, numVariants, localErrorCode);
839         if (U_FAILURE(localErrorCode)) {
840             bogus = true;
841             return;
842         }
843         body = Matcher(copiedSelectors, numSelectors, copiedVariants, numVariants);
844     }
845 
846     bindingsLen = other.bindingsLen;
847     if (bindingsLen > 0) {
848         bindings.adoptInstead(copyArray(other.bindings.getAlias(), bindingsLen, localErrorCode));
849     }
850     if (U_FAILURE(localErrorCode)) {
851         bogus = true;
852     }
853 }
854 
MFDataModel(const MFDataModel::Builder & builder,UErrorCode & errorCode)855 MFDataModel::MFDataModel(const MFDataModel::Builder& builder, UErrorCode& errorCode) noexcept : body(Pattern()) {
856     CHECK_ERROR(errorCode);
857 
858     if (builder.hasPattern) {
859         body.emplace<Pattern>(builder.pattern);
860     } else {
861         U_ASSERT(builder.variants != nullptr);
862         U_ASSERT(builder.selectors != nullptr);
863         int32_t numVariants = builder.variants->size();
864         int32_t numSelectors = builder.selectors->size();
865         LocalArray<Variant> variants(copyVectorToArray<Variant>(*builder.variants, errorCode), errorCode);
866         LocalArray<Expression> selectors(copyVectorToArray<Expression>(*builder.selectors, errorCode), errorCode);
867         if (U_FAILURE(errorCode)) {
868             bogus = true;
869             return;
870         }
871         body.emplace<Matcher>(Matcher(selectors.orphan(), numSelectors, variants.orphan(), numVariants));
872     }
873 
874     U_ASSERT(builder.bindings != nullptr);
875     bindingsLen = builder.bindings->size();
876     if (bindingsLen > 0) {
877         bindings.adoptInstead(copyVectorToArray<Binding>(*builder.bindings, errorCode));
878     }
879     if (U_FAILURE(errorCode)) {
880         bogus = true;
881     }
882 }
883 
MFDataModel()884 MFDataModel::MFDataModel() : body(Pattern()) {}
885 
operator =(MFDataModel other)886 MFDataModel& MFDataModel::operator=(MFDataModel other) noexcept {
887     U_ASSERT(!other.bogus);
888     swap(*this, other);
889     return *this;
890 }
891 
build(UErrorCode & errorCode) const892 MFDataModel MFDataModel::Builder::build(UErrorCode& errorCode) const noexcept {
893     if (U_FAILURE(errorCode)) {
894         return {};
895     }
896     if (!hasPattern && !hasSelectors) {
897         errorCode = U_INVALID_STATE_ERROR;
898     }
899     return MFDataModel(*this, errorCode);
900 }
901 
~MFDataModel()902 MFDataModel::~MFDataModel() {}
~Builder()903 MFDataModel::Builder::~Builder() {
904     if (selectors != nullptr) {
905         delete selectors;
906     }
907     if (variants != nullptr) {
908         delete variants;
909     }
910     if (bindings != nullptr) {
911         delete bindings;
912     }
913 }
914 } // namespace message2
915 
916 U_NAMESPACE_END
917 
918 #endif /* #if !UCONFIG_NO_MF2 */
919 
920 #endif /* #if !UCONFIG_NO_FORMATTING */
921