ICU 76.1 76.1
Loading...
Searching...
No Matches
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_FORMATTING
12
13#if !UCONFIG_NO_MF2
14
16#include "unicode/messageformat2_data_model_names.h"
17
18#ifndef U_HIDE_DEPRECATED_API
19
20#include <algorithm>
21#include <cstddef>
22#include <iterator>
23#include <optional>
24#include <variant>
25#include <vector>
26
27U_NAMESPACE_BEGIN
28
29class UVector;
30
31// Helpers
32
33// Note: this _must_ be declared `inline` or else gcc will generate code
34// for its instantiations, which needs to be avoided because it returns
35// a std::vector
36template<typename T>
37static inline std::vector<T> toStdVector(const T* arr, int32_t len) {
38 std::vector<T> result;
39 for (int32_t i = 0; i < len; i++) {
40 result.push_back(arr[i]);
41 }
42 return result;
43}
44
45#if defined(U_REAL_MSVC)
46#pragma warning(push)
47// Ignore warning 4251 as these templates are instantiated later in this file,
48// after the classes used to instantiate them have been defined.
49#pragma warning(disable: 4251)
50#endif
51
52namespace message2 {
53 class Checker;
54 class MFDataModel;
55 class MessageFormatter;
56 class Parser;
57 class Serializer;
58
59
60 namespace data_model {
61 class Binding;
62 class Literal;
63 class Operator;
64
76 class U_I18N_API Literal : public UObject {
77 public:
95 const UnicodeString& unquoted() const;
105 UBool isQuoted() const { return thisIsQuoted; }
117 Literal(UBool q, const UnicodeString& s) : thisIsQuoted(q), contents(s) {}
124 Literal(const Literal& other) : thisIsQuoted(other.thisIsQuoted), contents(other.contents) {}
133 friend inline void swap(Literal& l1, Literal& l2) noexcept {
134 using std::swap;
135
136 swap(l1.thisIsQuoted, l2.thisIsQuoted);
137 swap(l1.contents, l2.contents);
138 }
153 Literal() = default;
169 bool operator<(const Literal& other) const;
185 bool operator==(const Literal& other) const;
192 virtual ~Literal();
193
194 private:
195 /* const */ bool thisIsQuoted = false;
196 /* const */ UnicodeString contents;
197 };
198 } // namespace data_model
199} // namespace message2
200
202// Export an explicit template instantiation of the LocalPointer that is used as a
203// data member of various MFDataModel classes.
204// (When building DLLs for Windows this is required.)
205// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
206// for similar examples.)
207#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
210#endif
211#if defined(U_REAL_MSVC)
212#pragma warning(pop)
213#endif
215
217
219// Export an explicit template instantiation of the std::variants and std::optionals
220// that are used as a data member of various MFDataModel classes.
221// (When building DLLs for Windows this is required.)
222// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
223// for similar examples.)
224#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
225#if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
226struct U_I18N_API std::_Nontrivial_dummy_type;
227template class U_I18N_API std::_Variant_storage_<false, icu::UnicodeString, icu::message2::data_model::Literal>;
228#endif
229template class U_I18N_API std::variant<icu::UnicodeString, icu::message2::data_model::Literal>;
230template class U_I18N_API std::optional<std::variant<icu::UnicodeString, icu::message2::data_model::Literal>>;
231template class U_I18N_API std::optional<icu::message2::data_model::Literal>;
232#endif
234
236
237namespace message2 {
238 namespace data_model {
239
254 class U_I18N_API Operand : public UObject {
255 public:
264 UBool isVariable() const;
273 UBool isLiteral() const;
282 virtual UBool isNull() const;
292 const UnicodeString& asVariable() const;
302 const Literal& asLiteral() const;
310 Operand() : contents(std::nullopt) {}
320 explicit Operand(const UnicodeString& v) : contents(VariableName(v)) {}
330 explicit Operand(const Literal& l) : contents(l) {}
339 friend inline void swap(Operand& o1, Operand& o2) noexcept {
340 using std::swap;
341 (void) o1;
342 (void) o2;
343 swap(o1.contents, o2.contents);
344 }
351 virtual Operand& operator=(Operand) noexcept;
358 Operand(const Operand&);
365 virtual ~Operand();
366 private:
367 std::optional<std::variant<VariableName, Literal>> contents;
368 }; // class Operand
369
385 class U_I18N_API Key : public UObject {
386 public:
395 UBool isWildcard() const { return !contents.has_value(); }
405 const Literal& asLiteral() const;
412 Key(const Key& other) : contents(other.contents) {}
420 Key() : contents(std::nullopt) {}
430 explicit Key(const Literal& lit) : contents(lit) {}
439 friend inline void swap(Key& k1, Key& k2) noexcept {
440 using std::swap;
441
442 swap(k1.contents, k2.contents);
443 }
450 Key& operator=(Key) noexcept;
464 bool operator<(const Key& other) const;
478 bool operator==(const Key& other) const;
485 virtual ~Key();
486 private:
487 /* const */ std::optional<Literal> contents;
488 }; // class Key
489 } // namespace data_model
490} // namespace message2
491
493// Export an explicit template instantiation of the LocalPointer that is used as a
494// data member of various MFDataModel classes.
495// (When building DLLs for Windows this is required.)
496// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
497// for similar examples.)
498#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
499template class U_I18N_API LocalPointerBase<message2::data_model::Key>;
500template class U_I18N_API LocalArray<message2::data_model::Key>;
501#endif
503
504namespace message2 {
505 namespace data_model {
516 class U_I18N_API SelectorKeys : public UObject {
517 public:
528 std::vector<Key> getKeys() const {
529 return toStdVector<Key>(keys.getAlias(), len);
530 }
540 class U_I18N_API Builder : public UMemory {
541 private:
542 friend class SelectorKeys;
543 UVector* keys; // This is a raw pointer and not a LocalPointer<UVector> to avoid undefined behavior warnings,
544 // since UVector is forward-declared
545 // The vector owns its elements
546 public:
557 Builder& add(Key&& key, UErrorCode& status) noexcept;
570 SelectorKeys build(UErrorCode& status) const;
587 virtual ~Builder();
588 Builder(const Builder&) = delete;
589 Builder& operator=(const Builder&) = delete;
590 Builder(Builder&&) = delete;
591 Builder& operator=(Builder&&) = delete;
592 }; // class SelectorKeys::Builder
607 bool operator<(const SelectorKeys& other) const;
615 SelectorKeys() : len(0) {}
624 friend inline void swap(SelectorKeys& s1, SelectorKeys& s2) noexcept {
625 using std::swap;
626
627 swap(s1.len, s2.len);
628 swap(s1.keys, s2.keys);
629 }
636 SelectorKeys(const SelectorKeys& other);
643 SelectorKeys& operator=(SelectorKeys other) noexcept;
650 virtual ~SelectorKeys();
651 private:
652 friend class Builder;
653 friend class message2::Checker;
654 friend class message2::MessageFormatter;
655 friend class message2::Serializer;
656
657 /* const */ LocalArray<Key> keys;
658 /* const */ int32_t len;
659
660 const Key* getKeysInternal() const;
661 SelectorKeys(const UVector& ks, UErrorCode& status);
662 }; // class SelectorKeys
663
664
665 } // namespace data_model
666
667
668 namespace data_model {
669 class Operator;
670
679 class U_I18N_API Option : public UObject {
680 public:
689 const Operand& getValue() const { return rand; }
698 const UnicodeString& getName() const { return name; }
709 Option(const UnicodeString& n, Operand&& r) : name(n), rand(std::move(r)) {}
726 friend inline void swap(Option& o1, Option& o2) noexcept {
727 using std::swap;
728
729 swap(o1.name, o2.name);
730 swap(o1.rand, o2.rand);
731 }
752 virtual ~Option();
753 private:
754 /* const */ UnicodeString name;
755 /* const */ Operand rand;
756 }; // class Option
757 } // namespace data_model
758} // namespace message2
759
761// Export an explicit template instantiation of the LocalPointer that is used as a
762// data member of various MFDataModel classes.
763// (When building DLLs for Windows this is required.)
764// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
765// for similar examples.)
766#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
769#endif
771
772namespace message2 {
773 namespace data_model {
774 // Internal only
775 #ifndef U_IN_DOXYGEN
776 // Options
777 // This is a wrapper class around a vector of options that provides lookup operations
778 class U_I18N_API OptionMap : public UObject {
779 public:
780 int32_t size() const;
781 // Needs to take an error code b/c an earlier copy might have failed
782 const Option& getOption(int32_t, UErrorCode&) const;
783 friend inline void swap(OptionMap& m1, OptionMap& m2) noexcept {
784 using std::swap;
785
786 swap(m1.bogus, m2.bogus);
787 swap(m1.options, m2.options);
788 swap(m1.len, m2.len);
789 }
790 OptionMap() : len(0) {}
791 OptionMap(const OptionMap&);
792 OptionMap& operator=(OptionMap);
793 std::vector<Option> getOptions() const {
794 return toStdVector<Option>(options.getAlias(), len);
795 }
796 OptionMap(const UVector&, UErrorCode&);
797 OptionMap(Option*, int32_t);
798 virtual ~OptionMap();
799
800 class U_I18N_API Builder : public UObject {
801 private:
802 UVector* options;
803 bool checkDuplicates = true;
804 public:
805 Builder& add(Option&& opt, UErrorCode&);
806 Builder(UErrorCode&);
807 static Builder attributes(UErrorCode&);
808 // As this class is private, build() is destructive
809 OptionMap build(UErrorCode&);
810 friend inline void swap(Builder& m1, Builder& m2) noexcept {
811 using std::swap;
812
813 swap(m1.options, m2.options);
814 swap(m1.checkDuplicates, m2.checkDuplicates);
815 }
816 Builder(Builder&&);
817 Builder(const Builder&) = delete;
818 Builder& operator=(Builder) noexcept;
819 virtual ~Builder();
820 }; // class OptionMap::Builder
821 private:
822 friend class message2::Serializer;
823
824 bool bogus = false;
825 LocalArray<Option> options;
826 int32_t len;
827 }; // class OptionMap
828 #endif
829
830 } // namespace data_model
831} // namespace message2
832
833U_NAMESPACE_END
834
835U_NAMESPACE_BEGIN
836
837namespace message2 {
838 namespace data_model {
852 class U_I18N_API Operator : public UObject {
853 public:
862 const FunctionName& getFunctionName() const;
871 std::vector<Option> getOptions() const {
872 return options.getOptions();
873 }
883 class U_I18N_API Builder : public UMemory {
884 private:
885 friend class Operator;
886 FunctionName functionName;
887 OptionMap::Builder options;
888 public:
912 Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status) noexcept;
945 virtual ~Builder();
946 Builder(const Builder&) = delete;
947 Builder& operator=(const Builder&) = delete;
948 Builder(Builder&&) = delete;
949 Builder& operator=(Builder&&) = delete;
950 }; // class Operator::Builder
957 Operator(const Operator& other) noexcept;
966 friend inline void swap(Operator& o1, Operator& o2) noexcept {
967 using std::swap;
968
969 swap(o1.name, o2.name);
970 swap(o1.options, o2.options);
971 }
978 Operator& operator=(Operator) noexcept;
986 Operator() {}
993 virtual ~Operator();
994 private:
995 friend class Binding;
996 friend class Builder;
997 friend class message2::Checker;
998 friend class message2::MessageFormatter;
999 friend class message2::Serializer;
1000
1001 // Function call constructor
1002 Operator(const FunctionName& f, const UVector& options, UErrorCode&);
1003
1004 const OptionMap& getOptionsInternal() const;
1005 Operator(const FunctionName&, const OptionMap&);
1006
1007 /* const */ FunctionName name;
1008 /* const */ OptionMap options;
1009 }; // class Operator
1010 } // namespace data_model
1011} // namespace message2
1012
1013U_NAMESPACE_END
1014
1016// Export an explicit template instantiation of the std::optional that is used as a
1017// data member of various MFDataModel classes.
1018// (When building DLLs for Windows this is required.)
1019// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1020// for similar examples.)
1021#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1022template class U_I18N_API std::optional<icu::message2::data_model::Operator>;
1023#endif
1025
1026U_NAMESPACE_BEGIN
1027
1028namespace message2 {
1029 namespace data_model {
1030 // Internal only
1031 typedef enum UMarkupType {
1032 UMARKUP_OPEN = 0,
1033 UMARKUP_CLOSE,
1034 UMARKUP_STANDALONE,
1035 UMARKUP_COUNT
1036 } UMarkupType;
1037
1048 class U_I18N_API Markup : public UObject {
1049 public:
1058 UBool isOpen() const { return (type == UMARKUP_OPEN); }
1067 UBool isClose() const { return (type == UMARKUP_CLOSE); }
1076 UBool isStandalone() const { return (type == UMARKUP_STANDALONE); }
1085 const UnicodeString& getName() const { return name; }
1094 std::vector<Option> getOptions() const { return options.getOptions(); }
1103 std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1118 virtual ~Markup();
1128 class U_I18N_API Builder : public UMemory {
1129 private:
1130 friend class Markup;
1131
1132 UnicodeString name;
1133 OptionMap::Builder options;
1134 OptionMap::Builder attributes;
1135 UMarkupType type = UMARKUP_COUNT;
1136 public:
1146 Builder& setName(const UnicodeString& n) { name = n; return *this; }
1155 Builder& setOpen() { type = UMARKUP_OPEN; return *this; }
1164 Builder& setClose() { type = UMARKUP_CLOSE; return *this; }
1173 Builder& setStandalone() { type = UMARKUP_STANDALONE; return *this; }
1232 virtual ~Builder();
1233 Builder(const Builder&) = delete;
1234 Builder& operator=(const Builder&) = delete;
1235 Builder(Builder&&) = delete;
1236 Builder& operator=(Builder&&) = delete;
1237 }; // class Markup::Builder
1238
1239 private:
1240 friend class Builder;
1241 friend class message2::Serializer;
1242
1243 UMarkupType type;
1244 UnicodeString name;
1245 OptionMap options;
1246 OptionMap attributes;
1247 const OptionMap& getOptionsInternal() const { return options; }
1248 const OptionMap& getAttributesInternal() const { return attributes; }
1249 Markup(UMarkupType, UnicodeString, OptionMap&&, OptionMap&&);
1250 }; // class Markup
1251
1266 public:
1302 const Operator* getOperator(UErrorCode& status) const;
1312 const Operand& getOperand() const;
1321 std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1331 class U_I18N_API Builder : public UMemory {
1332 private:
1333 friend class Expression;
1334
1335 bool hasOperand = false;
1336 bool hasOperator = false;
1337 Operand rand;
1338 Operator rator;
1339 OptionMap::Builder attributes;
1340 public:
1407 virtual ~Builder();
1408 Builder(const Builder&) = delete;
1409 Builder& operator=(const Builder&) = delete;
1410 Builder(Builder&&) = delete;
1411 Builder& operator=(Builder&&) = delete;
1412 }; // class Expression::Builder
1421 friend inline void swap(Expression& e1, Expression& e2) noexcept {
1422 using std::swap;
1423
1424 swap(e1.rator, e2.rator);
1425 swap(e1.rand, e2.rand);
1426 swap(e1.attributes, e2.attributes);
1427 }
1456 virtual ~Expression();
1457 private:
1458 friend class message2::Serializer;
1459
1460 /*
1461 Internally, an expression is represented as the application of an optional operator to an operand.
1462 The operand is always present; for function calls with no operand, it's represented
1463 as an operand for which `isNull()` is true.
1464
1465 Operator | Operand
1466 --------------------------------
1467 { |42| :fun opt=value } => (FunctionName=fun, | Literal(quoted=true, contents="42")
1468 options={opt: value})
1469 { abcd } => null | Literal(quoted=false, contents="abcd")
1470 { : fun opt=value } => (FunctionName=fun,
1471 options={opt: value}) | NullOperand()
1472 */
1473
1474 Expression(const Operator &rAtor, const Operand &rAnd, const OptionMap& attrs) : rator(rAtor), rand(rAnd), attributes(attrs) {}
1475 Expression(const Operand &rAnd, const OptionMap& attrs) : rator(std::nullopt), rand(Operand(rAnd)), attributes(attrs) {}
1476 Expression(const Operator &rAtor, const OptionMap& attrs) : rator(rAtor), rand(), attributes(attrs) {}
1477 /* const */ std::optional<Operator> rator;
1478 /* const */ Operand rand;
1479 /* const */ OptionMap attributes;
1480 const OptionMap& getAttributesInternal() const { return attributes; }
1481 }; // class Expression
1482 } // namespace data_model
1483} // namespace message2
1484
1486// Export an explicit template instantiation of the LocalPointer that is used as a
1487// data member of various MFDataModel classes.
1488// (When building DLLs for Windows this is required.)
1489// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1490// for similar examples.)
1491#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1492template class U_I18N_API LocalPointerBase<message2::data_model::Expression>;
1493template class U_I18N_API LocalArray<message2::data_model::Expression>;
1494#endif
1496
1497namespace message2 {
1498 namespace data_model {
1499
1500 class Pattern;
1501
1502 // Despite the comments, `PatternPart` is internal-only
1513 class PatternPart : public UObject {
1514 public:
1523 UBool isText() const { return std::holds_alternative<UnicodeString>(piece); }
1532 UBool isMarkup() const { return std::holds_alternative<Markup>(piece); }
1541 UBool isExpression() const { return std::holds_alternative<Expression>(piece); }
1551 const Expression& contents() const;
1561 const Markup& asMarkup() const;
1571 const UnicodeString& asText() const;
1580 friend inline void swap(PatternPart& p1, PatternPart& p2) noexcept {
1581 using std::swap;
1582
1583 swap(p1.piece, p2.piece);
1584 }
1605 virtual ~PatternPart();
1615 explicit PatternPart(const UnicodeString& t) : piece(t) {}
1625 explicit PatternPart(Expression&& e) : piece(e) {}
1635 explicit PatternPart(Markup&& m) : piece(m) {}
1643 PatternPart() = default;
1644 private:
1645 friend class Pattern;
1646
1647 std::variant<UnicodeString, Expression, Markup> piece;
1648 }; // class PatternPart
1649 } // namespace data_model
1650} // namespace message2
1651
1653// Export an explicit template instantiation of the LocalPointer that is used as a
1654// data member of various MFDataModel classes.
1655// (When building DLLs for Windows this is required.)
1656// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
1657// for similar examples.)
1658#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1661#endif
1663
1664namespace message2 {
1665 namespace data_model {
1676 class U_I18N_API Pattern : public UObject {
1677 private:
1678 friend class PatternPart;
1679
1680 public:
1681 struct Iterator;
1691 Iterator begin() const {
1692 return Iterator(this, 0);
1693 }
1703 Iterator end() const {
1704 return Iterator(this, len);
1705 }
1715 class U_I18N_API Builder : public UMemory {
1716 private:
1717 friend class Pattern;
1718
1719 UVector* parts; // Not a LocalPointer for the same reason as in `SelectorKeys::Builder`
1720
1721 public:
1767 Pattern build(UErrorCode& status) const noexcept;
1784 virtual ~Builder();
1785 Builder(const Builder&) = delete;
1786 Builder& operator=(const Builder&) = delete;
1787 Builder(Builder&&) = delete;
1788 Builder& operator=(Builder&&) = delete;
1789 }; // class Pattern::Builder
1790
1798 Pattern() : parts(LocalArray<PatternPart>()) {}
1807 friend inline void swap(Pattern& p1, Pattern& p2) noexcept {
1808 using std::swap;
1809
1810 swap(p1.bogus, p2.bogus);
1811 swap(p1.len, p2.len);
1812 swap(p1.parts, p2.parts);
1813 }
1820 Pattern(const Pattern& other);
1827 Pattern& operator=(Pattern) noexcept;
1834 virtual ~Pattern();
1835
1846 private:
1847 using iterator_category = std::forward_iterator_tag;
1848 using difference_type = std::ptrdiff_t;
1849 using value_type = std::variant<UnicodeString, Expression, Markup>;
1850 using pointer = value_type*;
1851 using reference = const value_type&;
1852
1853 friend class Pattern;
1854 Iterator(const Pattern* p, int32_t i) : pos(i), pat(p) {}
1855 friend bool operator== (const Iterator& a, const Iterator& b) { return (a.pat == b.pat && a.pos == b.pos); }
1856
1857 int32_t pos;
1858 const Pattern* pat;
1859
1860 public:
1867 reference operator*() const {
1868 const PatternPart& part = pat->parts[pos];
1869 return patternContents(part);
1870 }
1877 Iterator operator++() { pos++; return *this; }
1884 friend bool operator!= (const Iterator& a, const Iterator& b) { return !(a == b); }
1885 }; // struct Iterator
1886
1887 private:
1888 friend class Builder;
1889 friend class message2::MessageFormatter;
1890 friend class message2::Serializer;
1891
1892 // Set to true if a copy constructor fails;
1893 // needed in order to distinguish an uninitialized
1894 // Pattern from a 0-length pattern
1895 bool bogus = false;
1896
1897 // Possibly-empty array of parts
1898 int32_t len = 0;
1900
1901 Pattern(const UVector& parts, UErrorCode& status);
1902 // Helper
1903 static void initParts(Pattern&, const Pattern&);
1904
1913 int32_t numParts() const;
1924 const PatternPart& getPart(int32_t i) const;
1925
1926 // Gets around not being able to declare Pattern::Iterator as a friend
1927 // in PatternPart
1928 static const std::variant<UnicodeString, Expression, Markup>&
1929 patternContents(const PatternPart& p) { return p.piece; }
1930 }; // class Pattern
1931
1942 class U_I18N_API Variant : public UObject {
1943 public:
1952 const Pattern& getPattern() const { return p; }
1961 const SelectorKeys& getKeys() const { return k; }
1973 Variant(const SelectorKeys& keys, Pattern&& pattern) : k(keys), p(std::move(pattern)) {}
1982 friend inline void swap(Variant& v1, Variant& v2) noexcept {
1983 using std::swap;
1984
1985 swap(v1.k, v2.k);
1986 swap(v1.p, v2.p);
1987 }
1994 Variant& operator=(Variant other) noexcept;
2002 Variant() = default;
2009 Variant(const Variant&);
2016 virtual ~Variant();
2017 private:
2018 /* const */ SelectorKeys k;
2019 /* const */ Pattern p;
2020 }; // class Variant
2021 } // namespace data_model
2022
2023 namespace data_model {
2034 class U_I18N_API Binding : public UObject {
2035 public:
2044 const Expression& getValue() const;
2053 const VariableName& getVariable() const { return var; }
2068 static Binding input(UnicodeString&& variableName, Expression&& rhs, UErrorCode& errorCode);
2076 UBool isLocal() const { return local; }
2086 Binding(const VariableName& v, Expression&& e) : var(v), expr(std::move(e)), local(true), annotation(nullptr) {}
2095 friend inline void swap(Binding& b1, Binding& b2) noexcept {
2096 using std::swap;
2097
2098 swap(b1.var, b2.var);
2099 swap(b1.expr, b2.expr);
2100 swap(b1.local, b2.local);
2101 b1.updateAnnotation();
2102 b2.updateAnnotation();
2103 }
2110 Binding(const Binding& other);
2117 Binding& operator=(Binding) noexcept;
2125 Binding() : local(true) {}
2132 virtual ~Binding();
2133 private:
2134 friend class message2::Checker;
2135 friend class message2::MessageFormatter;
2136 friend class message2::Parser;
2137 friend class message2::Serializer;
2138
2139 /* const */ VariableName var;
2140 /* const */ Expression expr;
2141 /* const */ bool local;
2142
2143 // The following field is always nullptr for a local
2144 // declaration, and possibly nullptr for an .input declaration
2145 // If non-null, the referent is a member of `expr` so
2146 // its lifetime is the same as the lifetime of the enclosing Binding
2147 // (as long as there's no mutation)
2148 const Operator* annotation = nullptr;
2149
2150 const OptionMap& getOptionsInternal() const;
2151
2152 bool hasAnnotation() const { return !local && (annotation != nullptr); }
2153 void updateAnnotation();
2154 }; // class Binding
2155 } // namespace data_model
2156} // namespace message2
2157
2159// Export an explicit template instantiation of the LocalPointer that is used as a
2160// data member of various MFDataModel classes.
2161// (When building DLLs for Windows this is required.)
2162// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
2163// for similar examples.)
2164#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
2165template class U_I18N_API LocalPointerBase<message2::data_model::Variant>;
2166template class U_I18N_API LocalPointerBase<message2::data_model::Binding>;
2167template class U_I18N_API LocalArray<message2::data_model::Variant>;
2168template class U_I18N_API LocalArray<message2::data_model::Binding>;
2169#endif
2171
2172namespace message2 {
2173 using namespace data_model;
2174
2175
2176 // Internal only
2177
2178 class MFDataModel;
2179
2180 #ifndef U_IN_DOXYGEN
2181 class Matcher : public UObject {
2182 public:
2183 Matcher& operator=(Matcher);
2184 Matcher(const Matcher&);
2193 friend inline void swap(Matcher& m1, Matcher& m2) noexcept {
2194 using std::swap;
2195
2196 if (m1.bogus) {
2197 m2.bogus = true;
2198 return;
2199 }
2200 if (m2.bogus) {
2201 m1.bogus = true;
2202 return;
2203 }
2204 swap(m1.selectors, m2.selectors);
2205 swap(m1.numSelectors, m2.numSelectors);
2206 swap(m1.variants, m2.variants);
2207 swap(m1.numVariants, m2.numVariants);
2208 }
2209 virtual ~Matcher();
2210 private:
2211
2212 friend class MFDataModel;
2213
2214 Matcher(Expression* ss, int32_t ns, Variant* vs, int32_t nv);
2215 Matcher() {}
2216
2217 // A Matcher may have numSelectors=0 and numVariants=0
2218 // (this is a data model error, but it's representable).
2219 // So we have to keep a separate flag to track failed copies.
2220 bool bogus = false;
2221
2222 // The expressions that are being matched on.
2223 LocalArray<Expression> selectors;
2224 // The number of selectors
2225 int32_t numSelectors = 0;
2226 // The list of `when` clauses (case arms).
2227 LocalArray<Variant> variants;
2228 // The number of variants
2229 int32_t numVariants = 0;
2230 }; // class Matcher
2231 #endif
2232} // namespace message2
2233
2234U_NAMESPACE_END
2235
2237// Export an explicit template instantiation of the std::variant that is used as a
2238// data member of various MFDataModel classes.
2239// (When building DLLs for Windows this is required.)
2240// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
2241// for similar examples.)
2242#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
2243#if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
2244template class U_I18N_API std::_Variant_storage_<false, icu::message2::Matcher,icu::message2::data_model::Pattern>;
2245#endif
2246template class U_I18N_API std::variant<icu::message2::Matcher,icu::message2::data_model::Pattern>;
2247#endif
2249
2250U_NAMESPACE_BEGIN
2251
2252namespace message2 {
2253 // -----------------------------------------------------------------------
2254 // Public MFDataModel class
2255
2272 class U_I18N_API MFDataModel : public UMemory {
2273 /*
2274 Classes that represent nodes in the data model are nested inside the
2275 `MFDataModel` class.
2276
2277 Classes such as `Expression`, `Pattern` and `VariantMap` are immutable and
2278 are constructed using the builder pattern.
2279
2280 Most classes representing nodes have copy constructors. This is because builders
2281 contain immutable data that must be copied when calling `build()`, since the builder
2282 could go out of scope before the immutable result of the builder does. Copying is
2283 also necessary to prevent unexpected mutation if intermediate builders are saved
2284 and mutated again after calling `build()`.
2285
2286 The copy constructors perform a deep copy, for example by copying the entire
2287 list of options for an `Operator` (and copying the entire underlying vector.)
2288 Some internal fields should be `const`, but are declared as non-`const` to make
2289 the copy constructor simpler to implement. (These are noted throughout.) In
2290 other words, those fields are `const` except during the execution of a copy
2291 constructor.
2292
2293 On the other hand, intermediate `Builder` methods that return a `Builder&`
2294 mutate the state of the builder, so in code like:
2295
2296 Expression::Builder& exprBuilder = Expression::builder()-> setOperand(foo);
2297 Expression::Builder& exprBuilder2 = exprBuilder.setOperator(bar);
2298
2299 the call to `setOperator()` would mutate `exprBuilder`, since `exprBuilder`
2300 and `exprBuilder2` are references to the same object.
2301
2302 An alternate choice would be to make `build()` destructive, so that copying would
2303 be unnecessary. Or, both copying and moving variants of `build()` could be
2304 provided. Copying variants of the intermediate `Builder` methods could be
2305 provided as well, if this proved useful.
2306 */
2307 public:
2316 std::vector<Binding> getLocalVariables() const {
2317 std::vector<Binding> result;
2318 if (!bogus) {
2319 return toStdVector<Binding>(bindings.getAlias(), bindingsLen);
2320 }
2321 return {};
2322 }
2331 const std::vector<Expression> getSelectors() const {
2332 if (std::holds_alternative<Pattern>(body)) {
2333 return {};
2334 }
2335 const Matcher* match = std::get_if<Matcher>(&body);
2336 // match must be non-null, given the previous check
2337 return toStdVector<Expression>(match->selectors.getAlias(), match->numSelectors);
2338 }
2347 std::vector<Variant> getVariants() const {
2348 // Return empty vector if no variants
2349 if (std::holds_alternative<Pattern>(body)) {
2350 return {};
2351 }
2352 const Matcher* match = std::get_if<Matcher>(&body);
2353 // match must be non-null, given the previous check
2354 return toStdVector<Variant>(match->variants.getAlias(), match->numVariants);
2355 return {};
2356 }
2366 const Pattern& getPattern() const;
2367
2375 class U_I18N_API Builder;
2376
2384 MFDataModel();
2393 friend inline void swap(MFDataModel& m1, MFDataModel& m2) noexcept {
2394 using std::swap;
2395
2396 if (m1.bogus) {
2397 m2.bogus = true;
2398 return;
2399 }
2400 if (m2.bogus) {
2401 m1.bogus = true;
2402 return;
2403 }
2404 swap(m1.body, m2.body);
2405 swap(m1.bindings, m2.bindings);
2406 swap(m1.bindingsLen, m2.bindingsLen);
2407 }
2414 MFDataModel& operator=(MFDataModel) noexcept;
2421 MFDataModel(const MFDataModel& other);
2428 virtual ~MFDataModel();
2429
2437 class U_I18N_API Builder : public UMemory {
2438 private:
2439 friend class MFDataModel;
2440
2441 void checkDuplicate(const VariableName&, UErrorCode&) const;
2442 void buildSelectorsMessage(UErrorCode&);
2443 bool hasPattern = true;
2444 bool hasSelectors = false;
2445 Pattern pattern;
2446 // The following members are not LocalPointers for the same reason as in SelectorKeys::Builder
2447 UVector* selectors = nullptr;
2448 UVector* variants = nullptr;
2449 UVector* bindings = nullptr;
2450 public:
2488 Builder& addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept;
2500 Builder& setPattern(Pattern&& pattern);
2520 MFDataModel build(UErrorCode& status) const noexcept;
2540 virtual ~Builder();
2541 Builder(const Builder&) = delete;
2542 Builder& operator=(const Builder&) = delete;
2543 Builder(Builder&&) = delete;
2544 Builder& operator=(Builder&&) = delete;
2545 }; // class Builder
2546
2547 private:
2548 friend class Checker;
2549 friend class MessageFormatter;
2550 friend class Serializer;
2551
2552 Pattern empty; // Provided so that `getPattern()` can return a result
2553 // if called on a selectors message
2554 bool hasPattern() const { return std::holds_alternative<Pattern>(body); }
2555
2556 bool bogus = false; // Set if a copy constructor fails
2557
2558 // A message body is either a matcher (selector list and variant list),
2559 // or a single pattern
2560 std::variant<Matcher, Pattern> body;
2561
2562 // Bindings for local variables
2563 /* const */ LocalArray<Binding> bindings;
2564 int32_t bindingsLen = 0;
2565
2566 const Binding* getLocalVariablesInternal() const;
2567 const Expression* getSelectorsInternal() const;
2568 const Variant* getVariantsInternal() const;
2569
2570 int32_t numSelectors() const {
2571 const Matcher* matcher = std::get_if<Matcher>(&body);
2572 return (matcher == nullptr ? 0 : matcher->numSelectors);
2573 }
2574 int32_t numVariants() const {
2575 const Matcher* matcher = std::get_if<Matcher>(&body);
2576 return (matcher == nullptr ? 0 : matcher->numVariants);
2577 }
2578
2579 // Helper
2580 void initBindings(const Binding*);
2581
2582 MFDataModel(const Builder& builder, UErrorCode&) noexcept;
2583 }; // class MFDataModel
2584
2585} // namespace message2
2586
2587U_NAMESPACE_END
2588
2589#endif // U_HIDE_DEPRECATED_API
2590
2591#endif /* #if !UCONFIG_NO_MF2 */
2592
2593#endif /* #if !UCONFIG_NO_FORMATTING */
2594
2595#endif /* U_SHOW_CPLUSPLUS_API */
2596
2597#endif // MESSAGEFORMAT_DATA_MODEL_H
2598
2599// eof
2600
"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 & 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 & addSelector(Expression &&selector, UErrorCode &errorCode) noexcept
Adds a selector expression.
Builder & setPattern(Pattern &&pattern)
Sets the body of the message as a pattern.
The mutable Expression::Builder class allows the operator to be constructed incrementally.
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 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 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.
An Option pairs an option name with an Operand.
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.
The mutable Pattern::Builder class allows the pattern to be constructed one part at a time.
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.
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.
C++ API: "Smart pointers" for use with and in ICU4C C++ code.
U_EXPORT UBool operator==(const StringPiece &x, const StringPiece &y)
Global operator == for StringPiece.
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