ICU 77.1 77.1
messageformat2_data_model.h
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#ifndef MESSAGEFORMAT_DATA_MODEL_H
7#define MESSAGEFORMAT_DATA_MODEL_H
8
9#if U_SHOW_CPLUSPLUS_API
10
11#if !UCONFIG_NO_NORMALIZATION
12
13#if !UCONFIG_NO_FORMATTING
14
15#if !UCONFIG_NO_MF2
16
18#include "unicode/messageformat2_data_model_names.h"
19
20#ifndef U_HIDE_DEPRECATED_API
21
22#include <algorithm>
23#include <cstddef>
24#include <iterator>
25#include <optional>
26#include <variant>
27#include <vector>
28
29U_NAMESPACE_BEGIN
30
31class UVector;
32
33// Helpers
34
35// Note: this _must_ be declared `inline` or else gcc will generate code
36// for its instantiations, which needs to be avoided because it returns
37// a std::vector
38template<typename T>
39static inline std::vector<T> toStdVector(const T* arr, int32_t len) {
40 std::vector<T> result;
41 for (int32_t i = 0; i < len; i++) {
42 result.push_back(arr[i]);
43 }
44 return result;
45}
46
47#if defined(U_REAL_MSVC)
48#pragma warning(push)
49// Ignore warning 4251 as these templates are instantiated later in this file,
50// after the classes used to instantiate them have been defined.
51#pragma warning(disable: 4251)
52#endif
53
54namespace message2 {
55 class Checker;
56 class MFDataModel;
57 class MessageFormatter;
58 class Parser;
59 class Serializer;
60
61
62 namespace data_model {
63 class Binding;
64 class Literal;
65 class Operator;
66
78 class U_I18N_API Literal : public UObject {
79 public:
97 const UnicodeString& unquoted() const;
107 UBool isQuoted() const { return thisIsQuoted; }
119 Literal(UBool q, const UnicodeString& s) : thisIsQuoted(q), contents(s) {}
126 Literal(const Literal& other) : thisIsQuoted(other.thisIsQuoted), contents(other.contents) {}
135 friend inline void swap(Literal& l1, Literal& l2) noexcept {
136 using std::swap;
137
138 swap(l1.thisIsQuoted, l2.thisIsQuoted);
139 swap(l1.contents, l2.contents);
140 }
141
155 Literal() = default;
171 bool operator<(const Literal& other) const;
187 bool operator==(const Literal& other) const;
194 virtual ~Literal();
195
196 private:
197 /* const */ bool thisIsQuoted = false;
198 /* const */ UnicodeString contents;
199 };
200 } // namespace data_model
201} // namespace message2
202
204// Export an explicit template instantiation of the LocalPointer that is used as a
205// data member of various MFDataModel classes.
206// (When building DLLs for Windows this is required.)
207// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
208// for similar examples.)
209#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
212#endif
213#if defined(U_REAL_MSVC)
214#pragma warning(pop)
215#endif
217
218U_NAMESPACE_END
219
221// Export an explicit template instantiation of the std::variants and std::optionals
222// that are used as a data member of various MFDataModel classes.
223// (When building DLLs for Windows this is required.)
224// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
225// for similar examples.)
226#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
227#if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
228struct U_I18N_API std::_Nontrivial_dummy_type;
229template class U_I18N_API std::_Variant_storage_<false, icu::UnicodeString, icu::message2::data_model::Literal>;
230#endif
231template class U_I18N_API std::variant<icu::UnicodeString, icu::message2::data_model::Literal>;
232template class U_I18N_API std::optional<std::variant<icu::UnicodeString, icu::message2::data_model::Literal>>;
233template class U_I18N_API std::optional<icu::message2::data_model::Literal>;
234#endif
236
237U_NAMESPACE_BEGIN
238
239namespace message2 {
240 namespace data_model {
241
256 class U_I18N_API Operand : public UObject {
257 public:
284 virtual UBool isNull() const;
294 const UnicodeString& asVariable() const;
304 const Literal& asLiteral() const;
312 Operand() : contents(std::nullopt) {}
322 explicit Operand(const UnicodeString& v) : contents(VariableName(v)) {}
332 explicit Operand(const Literal& l) : contents(l) {}
341 friend inline void swap(Operand& o1, Operand& o2) noexcept {
342 using std::swap;
343 (void) o1;
344 (void) o2;
345 swap(o1.contents, o2.contents);
346 }
347
353 virtual Operand& operator=(Operand) noexcept;
367 virtual ~Operand();
368 private:
369 std::optional<std::variant<VariableName, Literal>> contents;
370 }; // class Operand
371
387 class U_I18N_API Key : public UObject {
388 public:
397 UBool isWildcard() const { return !contents.has_value(); }
407 const Literal& asLiteral() const;
414 Key(const Key& other) : contents(other.contents) {}
422 Key() : contents(std::nullopt) {}
432 explicit Key(const Literal& lit) : contents(lit) {}
441 friend inline void swap(Key& k1, Key& k2) noexcept {
442 using std::swap;
443
444 swap(k1.contents, k2.contents);
445 }
446
452 Key& operator=(Key) noexcept;
466 bool operator<(const Key& other) const;
480 bool operator==(const Key& other) const;
487 virtual ~Key();
488 private:
489 /* const */ std::optional<Literal> contents;
490 }; // class Key
491 } // namespace data_model
492} // namespace message2
493
495// Export an explicit template instantiation of the LocalPointer that is used as a
496// data member of various MFDataModel classes.
497// (When building DLLs for Windows this is required.)
498// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
499// for similar examples.)
500#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
503#endif
505
506namespace message2 {
507 namespace data_model {
519 public:
530 std::vector<Key> getKeys() const {
531 return toStdVector<Key>(keys.getAlias(), len);
532 }
533
542 class U_I18N_API Builder : public UMemory {
543 private:
544 friend class SelectorKeys;
545 UVector* keys; // This is a raw pointer and not a LocalPointer<UVector> to avoid undefined behavior warnings,
546 // since UVector is forward-declared
547 // The vector owns its elements
548 public:
559 Builder& add(Key&& key, UErrorCode& status) noexcept;
572 SelectorKeys build(UErrorCode& status) const;
589 virtual ~Builder();
590 Builder(const Builder&) = delete;
591 Builder& operator=(const Builder&) = delete;
592 Builder(Builder&&) = delete;
593 Builder& operator=(Builder&&) = delete;
594 }; // class SelectorKeys::Builder
595
609 bool operator<(const SelectorKeys& other) const;
617 SelectorKeys() : len(0) {}
626 friend inline void swap(SelectorKeys& s1, SelectorKeys& s2) noexcept {
627 using std::swap;
628
629 swap(s1.len, s2.len);
630 swap(s1.keys, s2.keys);
631 }
632
652 virtual ~SelectorKeys();
653 private:
654 friend class Builder;
655 friend class message2::Checker;
656 friend class message2::MessageFormatter;
657 friend class message2::Serializer;
658
659 /* const */ LocalArray<Key> keys;
660 /* const */ int32_t len;
661
662 const Key* getKeysInternal() const;
663 SelectorKeys(const UVector& ks, UErrorCode& status);
664 }; // class SelectorKeys
665
666
667 } // namespace data_model
668
669
670 namespace data_model {
671 class Operator;
672
681 class U_I18N_API Option : public UObject {
682 public:
691 const Operand& getValue() const { return rand; }
700 const UnicodeString& getName() const { return name; }
711 Option(const UnicodeString& n, Operand&& r) : name(n), rand(std::move(r)) {}
728 friend inline void swap(Option& o1, Option& o2) noexcept {
729 using std::swap;
730
731 swap(o1.name, o2.name);
732 swap(o1.rand, o2.rand);
733 }
734
740 Option(const Option& other);
747 Option& operator=(Option other) noexcept;
754 virtual ~Option();
755 private:
756 /* const */ UnicodeString name;
757 /* const */ Operand rand;
758 }; // class Option
759 } // namespace data_model
760} // namespace message2
761
763// Export an explicit template instantiation of the LocalPointer that is used as a
764// data member of various MFDataModel classes.
765// (When building DLLs for Windows this is required.)
766// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
767// for similar examples.)
768#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
771#endif
773
774namespace message2 {
775 namespace data_model {
776 // Internal only
777 #ifndef U_IN_DOXYGEN
778 // Options
779 // This is a wrapper class around a vector of options that provides lookup operations
780 class U_I18N_API OptionMap : public UObject {
781 public:
782 int32_t size() const;
783 // Needs to take an error code b/c an earlier copy might have failed
784 const Option& getOption(int32_t, UErrorCode&) const;
785 friend inline void swap(OptionMap& m1, OptionMap& m2) noexcept {
786 using std::swap;
787
788 swap(m1.bogus, m2.bogus);
789 swap(m1.options, m2.options);
790 swap(m1.len, m2.len);
791 }
792 OptionMap() : len(0) {}
793 OptionMap(const OptionMap&);
794 OptionMap& operator=(OptionMap);
795 std::vector<Option> getOptions() const {
796 return toStdVector<Option>(options.getAlias(), len);
797 }
798 OptionMap(const UVector&, UErrorCode&);
799 OptionMap(Option*, int32_t);
800 virtual ~OptionMap();
801
802 class U_I18N_API Builder : public UObject {
803 private:
804 UVector* options;
805 bool checkDuplicates = true;
806 public:
807 Builder& add(Option&& opt, UErrorCode&);
808 Builder(UErrorCode&);
809 static Builder attributes(UErrorCode&);
810 // As this class is private, build() is destructive
811 OptionMap build(UErrorCode&);
812 friend inline void swap(Builder& m1, Builder& m2) noexcept {
813 using std::swap;
814
815 swap(m1.options, m2.options);
816 swap(m1.checkDuplicates, m2.checkDuplicates);
817 }
818 Builder(Builder&&);
819 Builder(const Builder&) = delete;
820 Builder& operator=(Builder) noexcept;
821 virtual ~Builder();
822 }; // class OptionMap::Builder
823 private:
824 friend class message2::Serializer;
825
826 bool bogus = false;
827 LocalArray<Option> options;
828 int32_t len;
829 }; // class OptionMap
830 #endif
831
832 } // namespace data_model
833} // namespace message2
834
835U_NAMESPACE_END
836
837U_NAMESPACE_BEGIN
838
839namespace message2 {
840 namespace data_model {
854 class U_I18N_API Operator : public UObject {
855 public:
864 const FunctionName& getFunctionName() const;
873 std::vector<Option> getOptions() const {
874 return options.getOptions();
875 }
876
885 class U_I18N_API Builder : public UMemory {
886 private:
887 friend class Operator;
888 FunctionName functionName;
889 OptionMap::Builder options;
890 public:
901 Builder& setFunctionName(FunctionName&& func);
914 Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status) noexcept;
930 Operator build(UErrorCode& status);
947 virtual ~Builder();
948 Builder(const Builder&) = delete;
949 Builder& operator=(const Builder&) = delete;
950 Builder(Builder&&) = delete;
951 Builder& operator=(Builder&&) = delete;
952 }; // class Operator::Builder
953
959 Operator(const Operator& other) noexcept;
968 friend inline void swap(Operator& o1, Operator& o2) noexcept {
969 using std::swap;
970
971 swap(o1.name, o2.name);
972 swap(o1.options, o2.options);
973 }
974
995 virtual ~Operator();
996 private:
997 friend class Binding;
998 friend class Builder;
999 friend class message2::Checker;
1000 friend class message2::MessageFormatter;
1001 friend class message2::Serializer;
1002
1003 // Function call constructor
1004 Operator(const FunctionName& f, const UVector& options, UErrorCode&);
1005
1006 const OptionMap& getOptionsInternal() const;
1007 Operator(const FunctionName&, const OptionMap&);
1008
1009 /* const */ FunctionName name;
1010 /* const */ OptionMap options;
1011 }; // class Operator
1012 } // namespace data_model
1013} // namespace message2
1014
1015U_NAMESPACE_END
1016
1018// Export an explicit template instantiation of the std::optional that is used as a
1019// data member of various MFDataModel classes.
1020// (When building DLLs for Windows this is required.)
1021// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1022// for similar examples.)
1023#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1024template class U_I18N_API std::optional<icu::message2::data_model::Operator>;
1025#endif
1027
1028U_NAMESPACE_BEGIN
1029
1030namespace message2 {
1031 namespace data_model {
1032 // Internal only
1033 typedef enum UMarkupType {
1034 UMARKUP_OPEN = 0,
1035 UMARKUP_CLOSE,
1036 UMARKUP_STANDALONE,
1037 UMARKUP_COUNT
1038 } UMarkupType;
1039
1050 class U_I18N_API Markup : public UObject {
1051 public:
1060 UBool isOpen() const { return (type == UMARKUP_OPEN); }
1069 UBool isClose() const { return (type == UMARKUP_CLOSE); }
1078 UBool isStandalone() const { return (type == UMARKUP_STANDALONE); }
1087 const UnicodeString& getName() const { return name; }
1096 std::vector<Option> getOptions() const { return options.getOptions(); }
1105 std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1120 virtual ~Markup();
1130 class U_I18N_API Builder : public UMemory {
1131 private:
1132 friend class Markup;
1133
1134 UnicodeString name;
1135 OptionMap::Builder options;
1136 OptionMap::Builder attributes;
1137 UMarkupType type = UMARKUP_COUNT;
1138 public:
1148 Builder& setName(const UnicodeString& n) { name = n; return *this; }
1157 Builder& setOpen() { type = UMARKUP_OPEN; return *this; }
1166 Builder& setClose() { type = UMARKUP_CLOSE; return *this; }
1175 Builder& setStandalone() { type = UMARKUP_STANDALONE; return *this; }
1187 Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status);
1199 Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1217 Markup build(UErrorCode& status);
1234 virtual ~Builder();
1235 Builder(const Builder&) = delete;
1236 Builder& operator=(const Builder&) = delete;
1237 Builder(Builder&&) = delete;
1238 Builder& operator=(Builder&&) = delete;
1239 }; // class Markup::Builder
1240
1241 private:
1242 friend class Builder;
1243 friend class message2::Serializer;
1244
1245 UMarkupType type;
1246 UnicodeString name;
1247 OptionMap options;
1248 OptionMap attributes;
1249 const OptionMap& getOptionsInternal() const { return options; }
1250 const OptionMap& getAttributesInternal() const { return attributes; }
1251 Markup(UMarkupType, UnicodeString, OptionMap&&, OptionMap&&);
1252 }; // class Markup
1253
1268 public:
1304 const Operator* getOperator(UErrorCode& status) const;
1314 const Operand& getOperand() const;
1323 std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1333 class U_I18N_API Builder : public UMemory {
1334 private:
1335 friend class Expression;
1336
1337 bool hasOperand = false;
1338 bool hasOperator = false;
1339 Operand rand;
1340 Operator rator;
1341 OptionMap::Builder attributes;
1342 public:
1374 Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1392 Expression build(UErrorCode& status);
1409 virtual ~Builder();
1410 Builder(const Builder&) = delete;
1411 Builder& operator=(const Builder&) = delete;
1412 Builder(Builder&&) = delete;
1413 Builder& operator=(Builder&&) = delete;
1414 }; // class Expression::Builder
1415
1423 friend inline void swap(Expression& e1, Expression& e2) noexcept {
1424 using std::swap;
1425
1426 swap(e1.rator, e2.rator);
1427 swap(e1.rand, e2.rand);
1428 swap(e1.attributes, e2.attributes);
1429 }
1430
1436 Expression(const Expression& other);
1458 virtual ~Expression();
1459 private:
1460 friend class message2::Serializer;
1461
1462 /*
1463 Internally, an expression is represented as the application of an optional operator to an operand.
1464 The operand is always present; for function calls with no operand, it's represented
1465 as an operand for which `isNull()` is true.
1466
1467 Operator | Operand
1468 --------------------------------
1469 { |42| :fun opt=value } => (FunctionName=fun, | Literal(quoted=true, contents="42")
1470 options={opt: value})
1471 { abcd } => null | Literal(quoted=false, contents="abcd")
1472 { : fun opt=value } => (FunctionName=fun,
1473 options={opt: value}) | NullOperand()
1474 */
1475
1476 Expression(const Operator &rAtor, const Operand &rAnd, const OptionMap& attrs) : rator(rAtor), rand(rAnd), attributes(attrs) {}
1477 Expression(const Operand &rAnd, const OptionMap& attrs) : rator(std::nullopt), rand(Operand(rAnd)), attributes(attrs) {}
1478 Expression(const Operator &rAtor, const OptionMap& attrs) : rator(rAtor), rand(), attributes(attrs) {}
1479 /* const */ std::optional<Operator> rator;
1480 /* const */ Operand rand;
1481 /* const */ OptionMap attributes;
1482 const OptionMap& getAttributesInternal() const { return attributes; }
1483 }; // class Expression
1484 } // namespace data_model
1485} // namespace message2
1486
1488// Export an explicit template instantiation of the LocalPointer that is used as a
1489// data member of various MFDataModel classes.
1490// (When building DLLs for Windows this is required.)
1491// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1492// for similar examples.)
1493#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1494template class U_I18N_API LocalPointerBase<message2::data_model::Expression>;
1495template class U_I18N_API LocalArray<message2::data_model::Expression>;
1496#endif
1498
1499namespace message2 {
1500 namespace data_model {
1501
1502 class Pattern;
1503
1504 // Despite the comments, `PatternPart` is internal-only
1515 class PatternPart : public UObject {
1516 public:
1525 UBool isText() const { return std::holds_alternative<UnicodeString>(piece); }
1534 UBool isMarkup() const { return std::holds_alternative<Markup>(piece); }
1543 UBool isExpression() const { return std::holds_alternative<Expression>(piece); }
1553 const Expression& contents() const;
1563 const Markup& asMarkup() const;
1573 const UnicodeString& asText() const;
1582 friend inline void swap(PatternPart& p1, PatternPart& p2) noexcept {
1583 using std::swap;
1584
1585 swap(p1.piece, p2.piece);
1586 }
1587
1607 virtual ~PatternPart();
1617 explicit PatternPart(const UnicodeString& t) : piece(t) {}
1627 explicit PatternPart(Expression&& e) : piece(e) {}
1637 explicit PatternPart(Markup&& m) : piece(m) {}
1645 PatternPart() = default;
1646 private:
1647 friend class Pattern;
1648
1649 std::variant<UnicodeString, Expression, Markup> piece;
1650 }; // class PatternPart
1651 } // namespace data_model
1652} // namespace message2
1653
1655// Export an explicit template instantiation of the LocalPointer that is used as a
1656// data member of various MFDataModel classes.
1657// (When building DLLs for Windows this is required.)
1658// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1659// for similar examples.)
1660#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1663#endif
1665
1666namespace message2 {
1667 namespace data_model {
1678 class U_I18N_API Pattern : public UObject {
1679 private:
1680 friend class PatternPart;
1681
1682 public:
1683 struct Iterator;
1693 Iterator begin() const {
1694 return Iterator(this, 0);
1695 }
1696
1705 Iterator end() const {
1706 return Iterator(this, len);
1707 }
1708
1717 class U_I18N_API Builder : public UMemory {
1718 private:
1719 friend class Pattern;
1720
1721 UVector* parts; // Not a LocalPointer for the same reason as in `SelectorKeys::Builder`
1722
1723 public:
1734 Builder& add(Expression&& part, UErrorCode& status) noexcept;
1745 Builder& add(Markup&& part, UErrorCode& status) noexcept;
1756 Builder& add(UnicodeString&& part, UErrorCode& status) noexcept;
1769 Pattern build(UErrorCode& status) const noexcept;
1786 virtual ~Builder();
1787 Builder(const Builder&) = delete;
1788 Builder& operator=(const Builder&) = delete;
1789 Builder(Builder&&) = delete;
1790 Builder& operator=(Builder&&) = delete;
1791 }; // class Pattern::Builder
1792
1800 Pattern() : parts(LocalArray<PatternPart>()) {}
1809 friend inline void swap(Pattern& p1, Pattern& p2) noexcept {
1810 using std::swap;
1811
1812 swap(p1.bogus, p2.bogus);
1813 swap(p1.len, p2.len);
1814 swap(p1.parts, p2.parts);
1815 }
1816
1822 Pattern(const Pattern& other);
1836 virtual ~Pattern();
1837
1847 struct U_I18N_API Iterator {
1848 private:
1849 using iterator_category = std::forward_iterator_tag;
1850 using difference_type = std::ptrdiff_t;
1851 using value_type = std::variant<UnicodeString, Expression, Markup>;
1852 using pointer = value_type*;
1853 using reference = const value_type&;
1854
1855 friend class Pattern;
1856 Iterator(const Pattern* p, int32_t i) : pos(i), pat(p) {}
1857 friend bool operator== (const Iterator& a, const Iterator& b) { return (a.pat == b.pat && a.pos == b.pos); }
1858
1859 int32_t pos;
1860 const Pattern* pat;
1861
1862 public:
1869 reference operator*() const {
1870 const PatternPart& part = pat->parts[pos];
1871 return patternContents(part);
1872 }
1873
1879 Iterator operator++() { pos++; return *this; }
1886 friend bool operator!= (const Iterator& a, const Iterator& b) { return !(a == b); }
1887 }; // struct Iterator
1888
1889 private:
1890 friend class Builder;
1891 friend class message2::MessageFormatter;
1892 friend class message2::Serializer;
1893
1894 // Set to true if a copy constructor fails;
1895 // needed in order to distinguish an uninitialized
1896 // Pattern from a 0-length pattern
1897 bool bogus = false;
1898
1899 // Possibly-empty array of parts
1900 int32_t len = 0;
1902
1903 Pattern(const UVector& parts, UErrorCode& status);
1904 // Helper
1905 static void initParts(Pattern&, const Pattern&);
1906
1915 int32_t numParts() const;
1926 const PatternPart& getPart(int32_t i) const;
1927
1928 // Gets around not being able to declare Pattern::Iterator as a friend
1929 // in PatternPart
1930 static const std::variant<UnicodeString, Expression, Markup>&
1931 patternContents(const PatternPart& p) { return p.piece; }
1932 }; // class Pattern
1933
1944 class U_I18N_API Variant : public UObject {
1945 public:
1954 const Pattern& getPattern() const { return p; }
1963 const SelectorKeys& getKeys() const { return k; }
1975 Variant(const SelectorKeys& keys, Pattern&& pattern) : k(keys), p(std::move(pattern)) {}
1984 friend inline void swap(Variant& v1, Variant& v2) noexcept {
1985 using std::swap;
1986
1987 swap(v1.k, v2.k);
1988 swap(v1.p, v2.p);
1989 }
1990
1996 Variant& operator=(Variant other) noexcept;
2004 Variant() = default;
2018 virtual ~Variant();
2019 private:
2020 /* const */ SelectorKeys k;
2021 /* const */ Pattern p;
2022 }; // class Variant
2023 } // namespace data_model
2024
2025 namespace data_model {
2036 class U_I18N_API Binding : public UObject {
2037 public:
2046 const Expression& getValue() const;
2055 const VariableName& getVariable() const { return var; }
2070 static Binding input(UnicodeString&& variableName, Expression&& rhs, UErrorCode& errorCode);
2078 UBool isLocal() const { return local; }
2088 Binding(const VariableName& v, Expression&& e) : var(v), expr(std::move(e)), local(true), annotation(nullptr) {}
2097 friend inline void swap(Binding& b1, Binding& b2) noexcept {
2098 using std::swap;
2099
2100 swap(b1.var, b2.var);
2101 swap(b1.expr, b2.expr);
2102 swap(b1.local, b2.local);
2103 b1.updateAnnotation();
2104 b2.updateAnnotation();
2105 }
2106
2112 Binding(const Binding& other);
2127 Binding() : local(true) {}
2134 virtual ~Binding();
2135 private:
2136 friend class message2::Checker;
2137 friend class message2::MessageFormatter;
2138 friend class message2::Parser;
2139 friend class message2::Serializer;
2140
2141 /* const */ VariableName var;
2142 /* const */ Expression expr;
2143 /* const */ bool local;
2144
2145 // The following field is always nullptr for a local
2146 // declaration, and possibly nullptr for an .input declaration
2147 // If non-null, the referent is a member of `expr` so
2148 // its lifetime is the same as the lifetime of the enclosing Binding
2149 // (as long as there's no mutation)
2150 const Operator* annotation = nullptr;
2151
2152 const OptionMap& getOptionsInternal() const;
2153
2154 bool hasAnnotation() const { return !local && (annotation != nullptr); }
2155 void updateAnnotation();
2156 }; // class Binding
2157 } // namespace data_model
2158} // namespace message2
2159
2161// Export an explicit template instantiation of the LocalPointer that is used as a
2162// data member of various MFDataModel classes.
2163// (When building DLLs for Windows this is required.)
2164// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
2165// for similar examples.)
2166#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
2167template class U_I18N_API LocalPointerBase<message2::data_model::Variant>;
2168template class U_I18N_API LocalPointerBase<message2::data_model::Binding>;
2169template class U_I18N_API LocalArray<message2::data_model::Variant>;
2170template class U_I18N_API LocalArray<message2::data_model::Binding>;
2171#endif
2173
2174namespace message2 {
2175 using namespace data_model;
2176
2177
2178 // Internal only
2179
2180 class MFDataModel;
2181
2182 #ifndef U_IN_DOXYGEN
2183 class Matcher : public UObject {
2184 public:
2185 Matcher& operator=(Matcher);
2186 Matcher(const Matcher&);
2195 friend inline void swap(Matcher& m1, Matcher& m2) noexcept {
2196 using std::swap;
2197
2198 if (m1.bogus) {
2199 m2.bogus = true;
2200 return;
2201 }
2202 if (m2.bogus) {
2203 m1.bogus = true;
2204 return;
2205 }
2206 swap(m1.selectors, m2.selectors);
2207 swap(m1.numSelectors, m2.numSelectors);
2208 swap(m1.variants, m2.variants);
2209 swap(m1.numVariants, m2.numVariants);
2210 }
2211 virtual ~Matcher();
2212 private:
2213
2214 friend class MFDataModel;
2215
2216 Matcher(VariableName* ss, int32_t ns, Variant* vs, int32_t nv);
2217 Matcher() {}
2218
2219 // A Matcher may have numSelectors=0 and numVariants=0
2220 // (this is a data model error, but it's representable).
2221 // So we have to keep a separate flag to track failed copies.
2222 bool bogus = false;
2223
2224 // The variables that are being matched on.
2225 LocalArray<VariableName> selectors;
2226 // The number of selectors
2227 int32_t numSelectors = 0;
2228 // The list of `when` clauses (case arms).
2229 LocalArray<Variant> variants;
2230 // The number of variants
2231 int32_t numVariants = 0;
2232 }; // class Matcher
2233 #endif
2234} // namespace message2
2235
2236U_NAMESPACE_END
2237
2239// Export an explicit template instantiation of the std::variant that is used as a
2240// data member of various MFDataModel classes.
2241// (When building DLLs for Windows this is required.)
2242// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
2243// for similar examples.)
2244#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
2245#if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
2246template class U_I18N_API std::_Variant_storage_<false, icu::message2::Matcher,icu::message2::data_model::Pattern>;
2247#endif
2248template class U_I18N_API std::variant<icu::message2::Matcher,icu::message2::data_model::Pattern>;
2249#endif
2251
2252U_NAMESPACE_BEGIN
2253
2254namespace message2 {
2255 // -----------------------------------------------------------------------
2256 // Public MFDataModel class
2257
2275 /*
2276 Classes that represent nodes in the data model are nested inside the
2277 `MFDataModel` class.
2278
2279 Classes such as `Expression`, `Pattern` and `VariantMap` are immutable and
2280 are constructed using the builder pattern.
2281
2282 Most classes representing nodes have copy constructors. This is because builders
2283 contain immutable data that must be copied when calling `build()`, since the builder
2284 could go out of scope before the immutable result of the builder does. Copying is
2285 also necessary to prevent unexpected mutation if intermediate builders are saved
2286 and mutated again after calling `build()`.
2287
2288 The copy constructors perform a deep copy, for example by copying the entire
2289 list of options for an `Operator` (and copying the entire underlying vector.)
2290 Some internal fields should be `const`, but are declared as non-`const` to make
2291 the copy constructor simpler to implement. (These are noted throughout.) In
2292 other words, those fields are `const` except during the execution of a copy
2293 constructor.
2294
2295 On the other hand, intermediate `Builder` methods that return a `Builder&`
2296 mutate the state of the builder, so in code like:
2297
2298 Expression::Builder& exprBuilder = Expression::builder()-> setOperand(foo);
2299 Expression::Builder& exprBuilder2 = exprBuilder.setOperator(bar);
2300
2301 the call to `setOperator()` would mutate `exprBuilder`, since `exprBuilder`
2302 and `exprBuilder2` are references to the same object.
2303
2304 An alternate choice would be to make `build()` destructive, so that copying would
2305 be unnecessary. Or, both copying and moving variants of `build()` could be
2306 provided. Copying variants of the intermediate `Builder` methods could be
2307 provided as well, if this proved useful.
2308 */
2309 public:
2318 std::vector<Binding> getLocalVariables() const {
2319 std::vector<Binding> result;
2320 if (!bogus) {
2321 return toStdVector<Binding>(bindings.getAlias(), bindingsLen);
2322 }
2323 return {};
2324 }
2325
2333 std::vector<VariableName> getSelectors() const {
2334 if (std::holds_alternative<Pattern>(body)) {
2335 return {};
2336 }
2337 const Matcher* match = std::get_if<Matcher>(&body);
2338 // match must be non-null, given the previous check
2339 return toStdVector<VariableName>(match->selectors.getAlias(), match->numSelectors);
2340 }
2341
2349 std::vector<Variant> getVariants() const {
2350 // Return empty vector if no variants
2351 if (std::holds_alternative<Pattern>(body)) {
2352 return {};
2353 }
2354 const Matcher* match = std::get_if<Matcher>(&body);
2355 // match must be non-null, given the previous check
2356 return toStdVector<Variant>(match->variants.getAlias(), match->numVariants);
2357 return {};
2358 }
2359
2368 const Pattern& getPattern() const;
2369
2378
2395 friend inline void swap(MFDataModel& m1, MFDataModel& m2) noexcept {
2396 using std::swap;
2397
2398 if (m1.bogus) {
2399 m2.bogus = true;
2400 return;
2401 }
2402 if (m2.bogus) {
2403 m1.bogus = true;
2404 return;
2405 }
2406 swap(m1.body, m2.body);
2407 swap(m1.bindings, m2.bindings);
2408 swap(m1.bindingsLen, m2.bindingsLen);
2409 }
2410
2430 virtual ~MFDataModel();
2431
2439 class U_I18N_API Builder : public UMemory {
2440 private:
2441 friend class MFDataModel;
2442
2443 void checkDuplicate(const VariableName&, UErrorCode&) const;
2444 void buildSelectorsMessage(UErrorCode&);
2445 bool hasPattern = true;
2446 bool hasSelectors = false;
2447 Pattern pattern;
2448 // The following members are not LocalPointers for the same reason as in SelectorKeys::Builder
2449 UVector* selectors = nullptr;
2450 UVector* variants = nullptr;
2451 UVector* bindings = nullptr;
2452 public:
2477 Builder& addSelector(VariableName&& selector, UErrorCode& errorCode);
2490 Builder& addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept;
2522 MFDataModel build(UErrorCode& status) const noexcept;
2542 virtual ~Builder();
2543 Builder(const Builder&) = delete;
2544 Builder& operator=(const Builder&) = delete;
2545 Builder(Builder&&) = delete;
2546 Builder& operator=(Builder&&) = delete;
2547 }; // class Builder
2548
2549 private:
2550 friend class Checker;
2551 friend class MessageFormatter;
2552 friend class Serializer;
2553
2554 Pattern empty; // Provided so that `getPattern()` can return a result
2555 // if called on a selectors message
2556 bool hasPattern() const { return std::holds_alternative<Pattern>(body); }
2557
2558 bool bogus = false; // Set if a copy constructor fails
2559
2560 // A message body is either a matcher (selector list and variant list),
2561 // or a single pattern
2562 std::variant<Matcher, Pattern> body;
2563
2564 // Bindings for local variables
2565 /* const */ LocalArray<Binding> bindings;
2566 int32_t bindingsLen = 0;
2567
2568 const Binding* getLocalVariablesInternal() const;
2569 const VariableName* getSelectorsInternal() const;
2570 const Variant* getVariantsInternal() const;
2571
2572 int32_t numSelectors() const {
2573 const Matcher* matcher = std::get_if<Matcher>(&body);
2574 return (matcher == nullptr ? 0 : matcher->numSelectors);
2575 }
2576 int32_t numVariants() const {
2577 const Matcher* matcher = std::get_if<Matcher>(&body);
2578 return (matcher == nullptr ? 0 : matcher->numVariants);
2579 }
2580
2581 // Helper
2582 void initBindings(const Binding*);
2583
2584 MFDataModel(const Builder& builder, UErrorCode&) noexcept;
2585 }; // class MFDataModel
2586
2587} // namespace message2
2588
2589U_NAMESPACE_END
2590
2591#endif // U_HIDE_DEPRECATED_API
2592
2593#endif /* #if !UCONFIG_NO_MF2 */
2594
2595#endif /* #if !UCONFIG_NO_FORMATTING */
2596
2597#endif /* #if !UCONFIG_NO_NORMALIZATION */
2598
2599#endif /* U_SHOW_CPLUSPLUS_API */
2600
2601#endif // MESSAGEFORMAT_DATA_MODEL_H
2602
2603// eof
2604
"Smart pointer" class, deletes objects via the C++ array delete[] operator.
"Smart pointer" base class; do not use directly: use LocalPointer etc.
UMemory is the common ICU base class.
Definition uobject.h:115
UObject is the common ICU "boilerplate" class.
Definition uobject.h:223
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition unistr.h:296
The mutable MFDataModel::Builder class allows the data model to be constructed incrementally.
Builder(UErrorCode &status)
Default constructor.
Builder & addSelector(VariableName &&selector, UErrorCode &errorCode)
Adds a selector variable.
Builder & addBinding(Binding &&b, UErrorCode &status)
Adds a binding, There must not already be a binding with the same name.
MFDataModel build(UErrorCode &status) const noexcept
Constructs a new immutable data model.
Builder & addVariant(SelectorKeys &&keys, Pattern &&pattern, UErrorCode &errorCode) noexcept
Adds a single variant.
Builder & setPattern(Pattern &&pattern)
Sets the body of the message as a pattern.
std::vector< Variant > getVariants() const
Accesses the variants.
std::vector< Binding > getLocalVariables() const
Accesses the local variable declarations for this data model.
MFDataModel & operator=(MFDataModel) noexcept
Assignment operator.
virtual ~MFDataModel()
Destructor.
const Pattern & getPattern() const
Accesses the pattern (in a message without selectors).
MFDataModel()
Default constructor.
std::vector< VariableName > getSelectors() const
Accesses the selectors.
friend void swap(MFDataModel &m1, MFDataModel &m2) noexcept
Non-member swap function.
MFDataModel(const MFDataModel &other)
Copy constructor.
A Binding pairs a variable name with an expression.
UBool isLocal() const
Returns true if and only if this binding represents a local declaration.
Binding(const Binding &other)
Copy constructor.
const VariableName & getVariable() const
Accesses the left-hand side of the binding.
Binding & operator=(Binding) noexcept
Copy assignment operator.
static Binding input(UnicodeString &&variableName, Expression &&rhs, UErrorCode &errorCode)
Constructor for input binding.
const Expression & getValue() const
Accesses the right-hand side of a binding.
Binding(const VariableName &v, Expression &&e)
Constructor.
friend void swap(Binding &b1, Binding &b2) noexcept
Non-member swap function.
Builder & addAttribute(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single attribute.
Expression build(UErrorCode &status)
Constructs a new immutable Expression using the operand and operator that were previously set.
Builder & setOperand(Operand &&rAnd)
Sets the operand of this expression.
Builder & setOperator(Operator &&rAtor)
Sets the operator of this expression.
Builder(UErrorCode &status)
Default constructor.
The Expression class corresponds to the expression nonterminal in the MessageFormat 2 grammar and the...
const Operand & getOperand() const
Accesses the operand of this expression.
UBool isFunctionCall() const
Checks if this expression has a function annotation (with or without an operand).
Expression & operator=(Expression) noexcept
Assignment operator.
UBool isStandaloneAnnotation() const
Checks if this expression is an annotation with no operand.
std::vector< Option > getAttributes() const
Gets the attributes of this expression.
Expression(const Expression &other)
Copy constructor.
const Operator * getOperator(UErrorCode &status) const
Accesses the function annotating this expression.
friend void swap(Expression &e1, Expression &e2) noexcept
Non-member swap function.
The Key class corresponds to the key nonterminal in the MessageFormat 2 grammar, https://github....
Key(const Key &other)
Copy constructor.
UBool isWildcard() const
Determines if this is a wildcard key.
virtual ~Key()
Destructor.
Key(const Literal &lit)
Literal key constructor.
Key()
Wildcard constructor; constructs a Key representing the catchall or wildcard key, '*'.
bool operator<(const Key &other) const
Less than operator.
bool operator==(const Key &other) const
Equality operator.
Key & operator=(Key) noexcept
Assignment operator.
const Literal & asLiteral() const
Returns the contents of this key as a literal.
friend void swap(Key &k1, Key &k2) noexcept
Non-member swap function.
The Literal class corresponds to the literal nonterminal in the MessageFormat 2 grammar,...
UBool isQuoted() const
Determines if this literal appeared as a quoted literal in the message.
const UnicodeString & unquoted() const
Returns the parsed string contents of this literal.
friend void swap(Literal &l1, Literal &l2) noexcept
Non-member swap function.
Literal(UBool q, const UnicodeString &s)
Literal constructor.
UnicodeString quoted() const
Returns the quoted representation of this literal (enclosed in '|' characters).
Literal()=default
Default constructor.
bool operator<(const Literal &other) const
Less than operator.
Literal(const Literal &other)
Copy constructor.
Literal & operator=(Literal) noexcept
Assignment operator.
bool operator==(const Literal &other) const
Equality operator.
The mutable Markup::Builder class allows the markup to be constructed incrementally.
Builder & setStandalone()
Sets this to be a standalone markup.
Builder & addOption(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single option.
Builder(UErrorCode &status)
Default constructor.
Builder & addAttribute(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single attribute.
Builder & setClose()
Sets this to be an closing markup.
Builder & setName(const UnicodeString &n)
Sets the name of this markup.
Markup build(UErrorCode &status)
Constructs a new immutable Markup using the name and type and (optionally) options and attributes tha...
Builder & setOpen()
Sets this to be an opening markup.
The Markup class corresponds to the markup nonterminal in the MessageFormat 2 grammar and the markup ...
std::vector< Option > getAttributes() const
Gets the attributes of this markup.
UBool isOpen() const
Checks if this markup is an opening tag.
std::vector< Option > getOptions() const
Gets the options of this markup.
UBool isClose() const
Checks if this markup is an closing tag.
virtual ~Markup()
Destructor.
const UnicodeString & getName() const
Gets the name of this markup.
UBool isStandalone() const
Checks if this markup is an standalone tag.
The Operand class corresponds to the operand nonterminal in the MessageFormat 2 grammar,...
virtual UBool isNull() const
Determines if this operand is the null operand.
virtual Operand & operator=(Operand) noexcept
Assignment operator.
const Literal & asLiteral() const
Returns a reference to this operand's literal contents.
friend void swap(Operand &o1, Operand &o2) noexcept
Non-member swap function.
Operand(const Literal &l)
Literal operand constructor.
UBool isVariable() const
Determines if this operand represents a variable.
UBool isLiteral() const
Determines if this operand represents a literal.
Operand(const UnicodeString &v)
Variable operand constructor.
Operand(const Operand &)
Copy constructor.
const UnicodeString & asVariable() const
Returns a reference to this operand's variable name.
The mutable Operator::Builder class allows the operator to be constructed incrementally.
Builder & setFunctionName(FunctionName &&func)
Sets this operator to be a function annotation and sets its name to func.
Operator build(UErrorCode &status)
Constructs a new immutable Operator using the function name and options that were previously set.
Builder & addOption(const UnicodeString &key, Operand &&value, UErrorCode &status) noexcept
Sets this operator to be a function annotation and adds a single option.
Builder(UErrorCode &status)
Default constructor.
The Operator class corresponds to the FunctionRef type in the Expression interface defined in https:/...
std::vector< Option > getOptions() const
Accesses function options.
Operator(const Operator &other) noexcept
Copy constructor.
const FunctionName & getFunctionName() const
Accesses the function name.
friend void swap(Operator &o1, Operator &o2) noexcept
Non-member swap function.
Operator & operator=(Operator) noexcept
Assignment operator.
Option(const Option &other)
Copy constructor.
virtual ~Option()
Destructor.
Option & operator=(Option other) noexcept
Assignment operator.
Option(const UnicodeString &n, Operand &&r)
Constructor.
const UnicodeString & getName() const
Accesses the left-hand side of the option.
const Operand & getValue() const
Accesses the right-hand side of the option.
friend void swap(Option &o1, Option &o2) noexcept
Non-member swap function.
A PatternPart is a single element (text or expression) in a Pattern.
UBool isExpression() const
Checks if the part is an expression part.
PatternPart(const UnicodeString &t)
Text part constructor.
const Expression & contents() const
Accesses the expression of the part.
PatternPart(Expression &&e)
Expression part constructor.
const UnicodeString & asText() const
Accesses the text contents of the part.
PatternPart()=default
Default constructor.
PatternPart(Markup &&m)
Markup part constructor.
UBool isMarkup() const
Checks if the part is a markup part.
UBool isText() const
Checks if the part is a text part.
const Markup & asMarkup() const
Accesses the expression of the part.
PatternPart(const PatternPart &other)
Copy constructor.
PatternPart & operator=(PatternPart) noexcept
Assignment operator.
friend void swap(PatternPart &p1, PatternPart &p2) noexcept
Non-member swap function.
Builder & add(UnicodeString &&part, UErrorCode &status) noexcept
Adds a single text part to the pattern.
Builder & add(Markup &&part, UErrorCode &status) noexcept
Adds a single markup part to the pattern.
Pattern build(UErrorCode &status) const noexcept
Constructs a new immutable Pattern using the list of parts set with previous add() calls.
Builder(UErrorCode &status)
Default constructor.
Builder & add(Expression &&part, UErrorCode &status) noexcept
Adds a single expression part to the pattern.
A Pattern is a sequence of formattable parts.
Iterator end() const
Returns a special value to mark the end of iteration.
Pattern(const Pattern &other)
Copy constructor.
friend void swap(Pattern &p1, Pattern &p2) noexcept
Non-member swap function.
Iterator begin() const
Returns the parts of this pattern.
Pattern & operator=(Pattern) noexcept
Assignment operator.
The mutable SelectorKeys::Builder class allows the key list to be constructed one key at a time.
Builder & add(Key &&key, UErrorCode &status) noexcept
Adds a single key to the list.
Builder(UErrorCode &status)
Default constructor.
SelectorKeys build(UErrorCode &status) const
Constructs a new immutable SelectorKeys using the list of keys set with previous add() calls.
The SelectorKeys class represents the key list for a single variant.
SelectorKeys & operator=(SelectorKeys other) noexcept
Assignment operator.
friend void swap(SelectorKeys &s1, SelectorKeys &s2) noexcept
Non-member swap function.
std::vector< Key > getKeys() const
Returns the underlying list of keys.
bool operator<(const SelectorKeys &other) const
Less than operator.
SelectorKeys(const SelectorKeys &other)
Copy constructor.
A Variant pairs a list of keys with a pattern It corresponds to the Variant interface defined in http...
Variant(const Variant &)
Copy constructor.
Variant & operator=(Variant other) noexcept
Assignment operator.
Variant(const SelectorKeys &keys, Pattern &&pattern)
Constructor.
const Pattern & getPattern() const
Accesses the pattern of the variant.
friend void swap(Variant &v1, Variant &v2) noexcept
Non-member swap function.
const SelectorKeys & getKeys() const
Accesses the keys of the variant.
Variant()=default
Default constructor.
C++ API: "Smart pointers" for use with and in ICU4C C++ code.
The Pattern::Iterator class provides an iterator over the formattable parts of a pattern.
reference operator*() const
Dereference operator (gets the element at the current iterator position).
Iterator operator++()
Increment operator (advances to the next iterator position).
int8_t UBool
The ICU boolean type, a signed-byte integer.
Definition umachine.h:247
Basic definitions for ICU, for both C and C++ APIs.
UErrorCode
Standard ICU4C error code type, a substitute for exceptions.
Definition utypes.h:430
#define U_I18N_API
Set to export library symbols from inside the i18n library, and to import them from outside.
Definition utypes.h:316