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