ICU 77.1  77.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
17 #include "unicode/localpointer.h"
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 
29 U_NAMESPACE_BEGIN
30 
31 class 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
38 template<typename T>
39 static 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 
54 namespace 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:
88  UnicodeString quoted() const;
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  }
147  Literal& operator=(Literal) noexcept;
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
216 
218 U_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)
228 struct U_I18N_API std::_Nontrivial_dummy_type;
229 template class U_I18N_API std::_Variant_storage_<false, icu::UnicodeString, icu::message2::data_model::Literal>;
230 #endif
231 template class U_I18N_API std::variant<icu::UnicodeString, icu::message2::data_model::Literal>;
232 template class U_I18N_API std::optional<std::variant<icu::UnicodeString, icu::message2::data_model::Literal>>;
233 template class U_I18N_API std::optional<icu::message2::data_model::Literal>;
234 #endif
235 
237 U_NAMESPACE_BEGIN
238 
239 namespace message2 {
240  namespace data_model {
241 
256  class U_I18N_API Operand : public UObject {
257  public:
266  UBool isVariable() const;
275  UBool isLiteral() const;
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  }
353  virtual Operand& operator=(Operand) noexcept;
360  Operand(const Operand&);
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  }
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
504 
506 namespace message2 {
507  namespace data_model {
518  class U_I18N_API SelectorKeys : public UObject {
519  public:
530  std::vector<Key> getKeys() const {
531  return toStdVector<Key>(keys.getAlias(), len);
532  }
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;
582  Builder(UErrorCode& status);
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
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  }
638  SelectorKeys(const SelectorKeys& other);
645  SelectorKeys& operator=(SelectorKeys other) noexcept;
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)) {}
719  Option() {}
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  }
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
769 template class U_I18N_API LocalPointerBase<message2::data_model::Option>;
770 template class U_I18N_API LocalArray<message2::data_model::Option>;
771 #endif
772 
774 namespace 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 
835 U_NAMESPACE_END
836 
837 U_NAMESPACE_BEGIN
838 
839 namespace 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  }
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);
940  Builder(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
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  }
980  Operator& operator=(Operator) noexcept;
988  Operator() {}
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 
1015 U_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
1024 template class U_I18N_API std::optional<icu::message2::data_model::Operator>;
1025 #endif
1026 
1028 U_NAMESPACE_BEGIN
1029 
1030 namespace 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(); }
1113  Markup() {}
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);
1227  Builder(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 
1267  class U_I18N_API Expression : public UObject {
1268  public:
1279  UBool isStandaloneAnnotation() const;
1290  UBool isFunctionCall() const;
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:
1352  Builder& setOperand(Operand&& rAnd);
1362  Builder& setOperator(Operator&& rAtor);
1374  Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1392  Expression build(UErrorCode& status);
1402  Builder(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
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  }
1436  Expression(const Expression& other);
1443  Expression& operator=(Expression) noexcept;
1451  Expression();
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
1494 template class U_I18N_API LocalPointerBase<message2::data_model::Expression>;
1495 template class U_I18N_API LocalArray<message2::data_model::Expression>;
1496 #endif
1497 
1499 namespace 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  }
1593  PatternPart(const PatternPart& other);
1600  PatternPart& operator=(PatternPart) noexcept;
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
1661 template class U_I18N_API LocalPointerBase<message2::data_model::PatternPart>;
1662 template class U_I18N_API LocalArray<message2::data_model::PatternPart>;
1663 #endif
1664 
1666 namespace 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  }
1705  Iterator end() const {
1706  return Iterator(this, len);
1707  }
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;
1779  Builder(UErrorCode& status);
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  }
1822  Pattern(const Pattern& other);
1829  Pattern& operator=(Pattern) noexcept;
1836  virtual ~Pattern();
1837 
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  }
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  }
1996  Variant& operator=(Variant other) noexcept;
2004  Variant() = default;
2011  Variant(const Variant&);
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  }
2112  Binding(const Binding& other);
2119  Binding& operator=(Binding) noexcept;
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
2167 template class U_I18N_API LocalPointerBase<message2::data_model::Variant>;
2168 template class U_I18N_API LocalPointerBase<message2::data_model::Binding>;
2169 template class U_I18N_API LocalArray<message2::data_model::Variant>;
2170 template class U_I18N_API LocalArray<message2::data_model::Binding>;
2171 #endif
2172 
2174 namespace 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 
2236 U_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)
2246 template class U_I18N_API std::_Variant_storage_<false, icu::message2::Matcher,icu::message2::data_model::Pattern>;
2247 #endif
2248 template class U_I18N_API std::variant<icu::message2::Matcher,icu::message2::data_model::Pattern>;
2249 #endif
2250 
2252 U_NAMESPACE_BEGIN
2253 
2254 namespace message2 {
2255  // -----------------------------------------------------------------------
2256  // Public MFDataModel class
2257 
2274  class U_I18N_API MFDataModel : public UMemory {
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  }
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  }
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  }
2368  const Pattern& getPattern() const;
2369 
2378 
2386  MFDataModel();
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  }
2416  MFDataModel& operator=(MFDataModel) noexcept;
2423  MFDataModel(const MFDataModel& other);
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:
2465  Builder& addBinding(Binding&& b, UErrorCode& status);
2477  Builder& addSelector(VariableName&& selector, UErrorCode& errorCode);
2490  Builder& addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept;
2502  Builder& setPattern(Pattern&& pattern);
2522  MFDataModel build(UErrorCode& status) const noexcept;
2535  Builder(UErrorCode& status);
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 
2589 U_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 
friend void swap(SelectorKeys &s1, SelectorKeys &s2) noexcept
Non-member swap function.
The mutable Markup::Builder class allows the markup to be constructed incrementally.
UBool isMarkup() const
Checks if the part is a markup part.
A Variant pairs a list of keys with a pattern It corresponds to the Variant interface defined in http...
A PatternPart is a single element (text or expression) in a Pattern.
UBool isExpression() const
Checks if the part is an expression part.
friend void swap(Variant &v1, Variant &v2) noexcept
Non-member swap function.
bool operator!=(const StringPiece &x, const StringPiece &y)
Global operator != for StringPiece.
Definition: stringpiece.h:346
Builder & setClose()
Sets this to be an closing markup.
Variant(const SelectorKeys &keys, Pattern &&pattern)
Constructor.
const VariableName & getVariable() const
Accesses the left-hand side of the binding.
std::vector< VariableName > getSelectors() const
Accesses the selectors.
Builder & setName(const UnicodeString &n)
Sets the name of this markup.
UBool isWildcard() const
Determines if this is a wildcard key.
Literal(const Literal &other)
Copy constructor.
U_EXPORT UBool operator==(const StringPiece &x, const StringPiece &y)
Global operator == for StringPiece.
friend void swap(Operator &o1, Operator &o2) noexcept
Non-member swap function.
Literal(UBool q, const UnicodeString &s)
Literal constructor.
UBool isOpen() const
Checks if this markup is an opening tag.
friend void swap(Literal &l1, Literal &l2) noexcept
Non-member swap function.
const Operand & getValue() const
Accesses the right-hand side of the option.
std::vector< Variant > getVariants() const
Accesses the variants.
std::vector< Binding > getLocalVariables() const
Accesses the local variable declarations for this data model.
Option(const UnicodeString &n, Operand &&r)
Constructor.
The Literal class corresponds to the literal nonterminal in the MessageFormat 2 grammar, https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf and the Literal interface defined in // https://github.com/unicode-org/message-format-wg/blob/main/spec/data-model.md#expressions.
An Option pairs an option name with an Operand.
const UnicodeString & getName() const
Gets the name of this markup.
The mutable Pattern::Builder class allows the pattern to be constructed one part at a time...
Iterator operator++()
Increment operator (advances to the next iterator position)
Key(const Literal &lit)
Literal key constructor.
#define U_I18N_API
Set to export library symbols from inside the i18n library, and to import them from outside...
Definition: utypes.h:316
Operand(const Literal &l)
Literal operand constructor.
The mutable SelectorKeys::Builder class allows the key list to be constructed one key at a time...
The Pattern::Iterator class provides an iterator over the formattable parts of a pattern.
friend void swap(Expression &e1, Expression &e2) noexcept
Non-member swap function.
std::vector< Key > getKeys() const
Returns the underlying list of keys.
The mutable Expression::Builder class allows the operator to be constructed incrementally.
The Markup class corresponds to the markup nonterminal in the MessageFormat 2 grammar and the markup ...
&quot;Smart pointer&quot; base class; do not use directly: use LocalPointer etc.
Definition: localpointer.h:68
Key(const Key &other)
Copy constructor.
C++ API: &quot;Smart pointers&quot; for use with and in ICU4C C++ code.
The MFDataModel class describes a parsed representation of the text of a message. ...
UBool isClose() const
Checks if this markup is an closing tag.
friend void swap(Option &o1, Option &o2) noexcept
Non-member swap function.
friend void swap(Binding &b1, Binding &b2) noexcept
Non-member swap function.
UBool isQuoted() const
Determines if this literal appeared as a quoted literal in the message.
&quot;Smart pointer&quot; class, deletes objects via the C++ array delete[] operator.
Definition: localpointer.h:366
const UnicodeString & getName() const
Accesses the left-hand side of the option.
const Pattern & getPattern() const
Accesses the pattern of the variant.
The Operator class corresponds to the FunctionRef type in the Expression interface defined in https:/...
friend void swap(Key &k1, Key &k2) noexcept
Non-member swap function.
friend void swap(MFDataModel &m1, MFDataModel &m2) noexcept
Non-member swap function.
PatternPart(Expression &&e)
Expression part constructor.
The mutable MFDataModel::Builder class allows the data model to be constructed incrementally.
Iterator end() const
Returns a special value to mark the end of iteration.
const SelectorKeys & getKeys() const
Accesses the keys of the variant.
PatternPart(Markup &&m)
Markup part constructor.
Key()
Wildcard constructor; constructs a Key representing the catchall or wildcard key, &#39;*&#39;...
The Operand class corresponds to the operand nonterminal in the MessageFormat 2 grammar, https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf .
Builder & setOpen()
Sets this to be an opening markup.
The Expression class corresponds to the expression nonterminal in the MessageFormat 2 grammar and the...
Binding(const VariableName &v, Expression &&e)
Constructor.
reference operator*() const
Dereference operator (gets the element at the current iterator position)
A Binding pairs a variable name with an expression.
UErrorCode
Standard ICU4C error code type, a substitute for exceptions.
Definition: utypes.h:430
The Key class corresponds to the key nonterminal in the MessageFormat 2 grammar, https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf .
Iterator begin() const
Returns the parts of this pattern.
std::vector< Option > getOptions() const
Accesses function options.
Operand(const UnicodeString &v)
Variable operand constructor.
Basic definitions for ICU, for both C and C++ APIs.
A Pattern is a sequence of formattable parts.
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition: unistr.h:295
std::vector< Option > getAttributes() const
Gets the attributes of this markup.
UBool isLocal() const
Returns true if and only if this binding represents a local declaration.
The SelectorKeys class represents the key list for a single variant.
std::vector< Option > getOptions() const
Gets the options of this markup.
friend void swap(PatternPart &p1, PatternPart &p2) noexcept
Non-member swap function.
UBool isStandalone() const
Checks if this markup is an standalone tag.
UObject is the common ICU &quot;boilerplate&quot; class.
Definition: uobject.h:223
std::vector< Option > getAttributes() const
Gets the attributes of this expression.
UMemory is the common ICU base class.
Definition: uobject.h:115
Builder & setStandalone()
Sets this to be a standalone markup.
friend void swap(Operand &o1, Operand &o2) noexcept
Non-member swap function.
UBool isText() const
Checks if the part is a text part.
int8_t UBool
The ICU boolean type, a signed-byte integer.
Definition: umachine.h:247
friend void swap(Pattern &p1, Pattern &p2) noexcept
Non-member swap function.
The mutable Operator::Builder class allows the operator to be constructed incrementally.