ICU 78.1  78.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 
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 MessageFormatter;
57  class Parser;
58  class Serializer;
59 
60 
61  namespace data_model {
62  class Binding;
63  class Literal;
64  class Operator;
65  class MFDataModel;
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  }
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 
216  public:
243  U_I18N_API virtual UBool isNull() const;
263  U_I18N_API const Literal& asLiteral() const;
271  U_I18N_API Operand() : contents(std::nullopt) {}
281  U_I18N_API explicit Operand(const UnicodeString& v) : contents(VariableName(v)) {}
291  U_I18N_API explicit Operand(const Literal& l) : contents(l) {}
300  U_I18N_API friend inline void swap(Operand& o1, Operand& o2) noexcept {
301  using std::swap;
302  (void) o1;
303  (void) o2;
304  swap(o1.contents, o2.contents);
305  }
312  U_I18N_API virtual Operand& operator=(Operand) noexcept;
326  U_I18N_API virtual ~Operand();
327  private:
328  std::optional<std::variant<VariableName, Literal>> contents;
329  }; // class Operand
330 
346  class U_I18N_API_CLASS Key : public UObject {
347  public:
356  U_I18N_API UBool isWildcard() const { return !contents.has_value(); }
366  U_I18N_API const Literal& asLiteral() const;
373  U_I18N_API Key(const Key& other) : contents(other.contents) {}
381  U_I18N_API Key() : contents(std::nullopt) {}
391  U_I18N_API explicit Key(const Literal& lit) : contents(lit) {}
400  U_I18N_API friend inline void swap(Key& k1, Key& k2) noexcept {
401  using std::swap;
402 
403  swap(k1.contents, k2.contents);
404  }
425  U_I18N_API bool operator<(const Key& other) const;
439  U_I18N_API bool operator==(const Key& other) const;
446  U_I18N_API virtual ~Key();
447  private:
448  /* const */ std::optional<Literal> contents;
449  }; // class Key
450 
462  public:
473  U_I18N_API std::vector<Key> getKeys() const {
474  return toStdVector<Key>(keys.getAlias(), len);
475  }
485  class U_I18N_API Builder : public UMemory {
486  private:
487  friend class SelectorKeys;
488  UVector* keys; // This is a raw pointer and not a LocalPointer<UVector> to avoid undefined behavior warnings,
489  // since UVector is forward-declared
490  // The vector owns its elements
491  public:
502  Builder& add(Key&& key, UErrorCode& status) noexcept;
515  SelectorKeys build(UErrorCode& status) const;
525  Builder(UErrorCode& status);
532  virtual ~Builder();
533  Builder(const Builder&) = delete;
534  Builder& operator=(const Builder&) = delete;
535  Builder(Builder&&) = delete;
536  Builder& operator=(Builder&&) = delete;
537  }; // class SelectorKeys::Builder
552  U_I18N_API bool operator<(const SelectorKeys& other) const;
560  U_I18N_API SelectorKeys() : len(0) {}
569  U_I18N_API friend inline void swap(SelectorKeys& s1, SelectorKeys& s2) noexcept {
570  using std::swap;
571 
572  swap(s1.len, s2.len);
573  swap(s1.keys, s2.keys);
574  }
596  private:
597  friend class Builder;
598  friend class message2::Checker;
599  friend class message2::MessageFormatter;
600  friend class message2::Serializer;
601 
602  /* const */ LocalArray<Key> keys;
603  /* const */ int32_t len;
604 
605  const Key* getKeysInternal() const;
606  SelectorKeys(const UVector& ks, UErrorCode& status);
607  }; // class SelectorKeys
608 
609  class Operator;
610 
619  class U_I18N_API Option : public UObject {
620  public:
629  const Operand& getValue() const { return rand; }
638  const UnicodeString& getName() const { return name; }
649  Option(const UnicodeString& n, Operand&& r) : name(n), rand(std::move(r)) {}
657  Option() {}
666  friend inline void swap(Option& o1, Option& o2) noexcept {
667  using std::swap;
668 
669  swap(o1.name, o2.name);
670  swap(o1.rand, o2.rand);
671  }
678  Option(const Option& other);
685  Option& operator=(Option other) noexcept;
692  virtual ~Option();
693  private:
694  /* const */ UnicodeString name;
695  /* const */ Operand rand;
696  }; // class Option
697 
698  // Internal only
699  #ifndef U_IN_DOXYGEN
700  // Options
701  // This is a wrapper class around a vector of options that provides lookup operations
702  class U_I18N_API_CLASS OptionMap : public UObject {
703  public:
704  U_I18N_API int32_t size() const;
705  // Needs to take an error code b/c an earlier copy might have failed
706  U_I18N_API const Option& getOption(int32_t, UErrorCode&) const;
707  U_I18N_API friend inline void swap(OptionMap& m1, OptionMap& m2) noexcept {
708  using std::swap;
709 
710  swap(m1.bogus, m2.bogus);
711  swap(m1.options, m2.options);
712  swap(m1.len, m2.len);
713  }
714  U_I18N_API OptionMap() : len(0) {}
715  U_I18N_API OptionMap(const OptionMap&);
716  U_I18N_API OptionMap& operator=(OptionMap);
717  U_I18N_API std::vector<Option> getOptions() const {
718  return toStdVector<Option>(options.getAlias(), len);
719  }
720  U_I18N_API OptionMap(const UVector&, UErrorCode&);
721  U_I18N_API OptionMap(Option*, int32_t);
722  U_I18N_API virtual ~OptionMap();
723 
724  class U_I18N_API Builder : public UObject {
725  private:
726  UVector* options;
727  bool checkDuplicates = true;
728  public:
729  Builder& add(Option&& opt, UErrorCode&);
730  Builder(UErrorCode&);
731  static Builder attributes(UErrorCode&);
732  // As this class is private, build() is destructive
733  OptionMap build(UErrorCode&);
734  friend inline void swap(Builder& m1, Builder& m2) noexcept {
735  using std::swap;
736 
737  swap(m1.options, m2.options);
738  swap(m1.checkDuplicates, m2.checkDuplicates);
739  }
740  Builder(Builder&&);
741  Builder(const Builder&) = delete;
742  Builder& operator=(Builder) noexcept;
743  virtual ~Builder();
744  }; // class OptionMap::Builder
745  private:
746  friend class message2::Serializer;
747 
748  bool bogus = false;
749  LocalArray<Option> options;
750  int32_t len;
751  }; // class OptionMap
752  #endif
753 
767  class U_I18N_API Operator : public UObject {
768  public:
786  std::vector<Option> getOptions() const {
787  return options.getOptions();
788  }
798  class U_I18N_API Builder : public UMemory {
799  private:
800  friend class Operator;
801  FunctionName functionName;
802  OptionMap::Builder options;
803  public:
827  Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status) noexcept;
853  Builder(UErrorCode& status);
860  virtual ~Builder();
861  Builder(const Builder&) = delete;
862  Builder& operator=(const Builder&) = delete;
863  Builder(Builder&&) = delete;
864  Builder& operator=(Builder&&) = delete;
865  }; // class Operator::Builder
872  Operator(const Operator& other) noexcept;
881  friend inline void swap(Operator& o1, Operator& o2) noexcept {
882  using std::swap;
883 
884  swap(o1.name, o2.name);
885  swap(o1.options, o2.options);
886  }
901  Operator() {}
908  virtual ~Operator();
909  private:
910  friend class Binding;
911  friend class Builder;
912  friend class message2::Checker;
913  friend class message2::MessageFormatter;
914  friend class message2::Serializer;
915 
916  // Function call constructor
917  Operator(const FunctionName& f, const UVector& options, UErrorCode&);
918 
919  const OptionMap& getOptionsInternal() const;
920  Operator(const FunctionName&, const OptionMap&);
921 
922  /* const */ FunctionName name;
923  /* const */ OptionMap options;
924  }; // class Operator
925 
926  // Internal only
927  typedef enum UMarkupType {
928  UMARKUP_OPEN = 0,
929  UMARKUP_CLOSE,
930  UMARKUP_STANDALONE,
931  UMARKUP_COUNT
932  } UMarkupType;
933 
944  class U_I18N_API Markup : public UObject {
945  public:
954  UBool isOpen() const { return (type == UMARKUP_OPEN); }
963  UBool isClose() const { return (type == UMARKUP_CLOSE); }
972  UBool isStandalone() const { return (type == UMARKUP_STANDALONE); }
981  const UnicodeString& getName() const { return name; }
990  std::vector<Option> getOptions() const { return options.getOptions(); }
999  std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1007  Markup() {}
1014  virtual ~Markup();
1024  class U_I18N_API Builder : public UMemory {
1025  private:
1026  friend class Markup;
1027 
1028  UnicodeString name;
1029  OptionMap::Builder options;
1030  OptionMap::Builder attributes;
1031  UMarkupType type = UMARKUP_COUNT;
1032  public:
1042  Builder& setName(const UnicodeString& n) { name = n; return *this; }
1051  Builder& setOpen() { type = UMARKUP_OPEN; return *this; }
1060  Builder& setClose() { type = UMARKUP_CLOSE; return *this; }
1069  Builder& setStandalone() { type = UMARKUP_STANDALONE; return *this; }
1081  Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status);
1093  Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1128  virtual ~Builder();
1129  Builder(const Builder&) = delete;
1130  Builder& operator=(const Builder&) = delete;
1131  Builder(Builder&&) = delete;
1132  Builder& operator=(Builder&&) = delete;
1133  }; // class Markup::Builder
1134 
1135  private:
1136  friend class Builder;
1137  friend class message2::Serializer;
1138 
1139  UMarkupType type;
1140  UnicodeString name;
1141  OptionMap options;
1142  OptionMap attributes;
1143  const OptionMap& getOptionsInternal() const { return options; }
1144  const OptionMap& getAttributesInternal() const { return attributes; }
1145  Markup(UMarkupType, UnicodeString, OptionMap&&, OptionMap&&);
1146  }; // class Markup
1147 
1162  public:
1217  U_I18N_API std::vector<Option> getAttributes() const { return attributes.getOptions(); }
1227  class U_I18N_API Builder : public UMemory {
1228  private:
1229  friend class Expression;
1230 
1231  bool hasOperand = false;
1232  bool hasOperator = false;
1233  Operand rand;
1234  Operator rator;
1235  OptionMap::Builder attributes;
1236  public:
1268  Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1303  virtual ~Builder();
1304  Builder(const Builder&) = delete;
1305  Builder& operator=(const Builder&) = delete;
1306  Builder(Builder&&) = delete;
1307  Builder& operator=(Builder&&) = delete;
1308  }; // class Expression::Builder
1317  U_I18N_API friend inline void swap(Expression& e1, Expression& e2) noexcept {
1318  using std::swap;
1319 
1320  swap(e1.rator, e2.rator);
1321  swap(e1.rand, e2.rand);
1322  swap(e1.attributes, e2.attributes);
1323  }
1353  private:
1354  friend class message2::Serializer;
1355 
1356  /*
1357  Internally, an expression is represented as the application of an optional operator to an operand.
1358  The operand is always present; for function calls with no operand, it's represented
1359  as an operand for which `isNull()` is true.
1360 
1361  Operator | Operand
1362  --------------------------------
1363  { |42| :fun opt=value } => (FunctionName=fun, | Literal(quoted=true, contents="42")
1364  options={opt: value})
1365  { abcd } => null | Literal(quoted=false, contents="abcd")
1366  { : fun opt=value } => (FunctionName=fun,
1367  options={opt: value}) | NullOperand()
1368  */
1369 
1370  Expression(const Operator &rAtor, const Operand &rAnd, const OptionMap& attrs) : rator(rAtor), rand(rAnd), attributes(attrs) {}
1371  Expression(const Operand &rAnd, const OptionMap& attrs) : rator(std::nullopt), rand(Operand(rAnd)), attributes(attrs) {}
1372  Expression(const Operator &rAtor, const OptionMap& attrs) : rator(rAtor), rand(), attributes(attrs) {}
1373  /* const */ std::optional<Operator> rator;
1374  /* const */ Operand rand;
1375  /* const */ OptionMap attributes;
1376  const OptionMap& getAttributesInternal() const { return attributes; }
1377  }; // class Expression
1378 
1379  class Pattern;
1380 
1381  // Despite the comments, `PatternPart` is internal-only
1393  public:
1402  U_I18N_API UBool isText() const { return std::holds_alternative<UnicodeString>(piece); }
1411  U_I18N_API UBool isMarkup() const { return std::holds_alternative<Markup>(piece); }
1420  U_I18N_API UBool isExpression() const { return std::holds_alternative<Expression>(piece); }
1440  U_I18N_API const Markup& asMarkup() const;
1459  U_I18N_API friend inline void swap(PatternPart& p1, PatternPart& p2) noexcept {
1460  using std::swap;
1461 
1462  swap(p1.piece, p2.piece);
1463  }
1494  U_I18N_API explicit PatternPart(const UnicodeString& t) : piece(t) {}
1504  U_I18N_API explicit PatternPart(Expression&& e) : piece(e) {}
1514  U_I18N_API explicit PatternPart(Markup&& m) : piece(m) {}
1523  private:
1524  friend class Pattern;
1525 
1526  std::variant<UnicodeString, Expression, Markup> piece;
1527  }; // class PatternPart
1528 
1540  private:
1541  friend class PatternPart;
1542 
1543  public:
1544  #ifndef U_IN_DOXYGEN
1545  struct U_I18N_API Iterator;
1546  #endif
1557  return Iterator(this, 0);
1558  }
1569  return Iterator(this, len);
1570  }
1580  class U_I18N_API Builder : public UMemory {
1581  private:
1582  friend class Pattern;
1583 
1584  UVector* parts; // Not a LocalPointer for the same reason as in `SelectorKeys::Builder`
1585 
1586  public:
1597  Builder& add(Expression&& part, UErrorCode& status) noexcept;
1608  Builder& add(Markup&& part, UErrorCode& status) noexcept;
1619  Builder& add(UnicodeString&& part, UErrorCode& status) noexcept;
1632  Pattern build(UErrorCode& status) const noexcept;
1649  virtual ~Builder();
1650  Builder(const Builder&) = delete;
1651  Builder& operator=(const Builder&) = delete;
1652  Builder(Builder&&) = delete;
1653  Builder& operator=(Builder&&) = delete;
1654  }; // class Pattern::Builder
1655 
1672  U_I18N_API friend inline void swap(Pattern& p1, Pattern& p2) noexcept {
1673  using std::swap;
1674 
1675  swap(p1.bogus, p2.bogus);
1676  swap(p1.len, p2.len);
1677  swap(p1.parts, p2.parts);
1678  }
1685  U_I18N_API Pattern(const Pattern& other);
1700 
1711  private:
1712  using iterator_category = std::forward_iterator_tag;
1713  using difference_type = std::ptrdiff_t;
1714  using value_type = std::variant<UnicodeString, Expression, Markup>;
1715  using pointer = value_type*;
1716  using reference = const value_type&;
1717 
1718  friend class Pattern;
1719  Iterator(const Pattern* p, int32_t i) : pos(i), pat(p) {}
1720  friend bool operator== (const Iterator& a, const Iterator& b) { return (a.pat == b.pat && a.pos == b.pos); }
1721 
1722  int32_t pos;
1723  const Pattern* pat;
1724 
1725  public:
1732  reference operator*() const {
1733  const PatternPart& part = pat->parts[pos];
1734  return patternContents(part);
1735  }
1742  Iterator operator++() { pos++; return *this; }
1749  friend bool operator!= (const Iterator& a, const Iterator& b) { return !(a == b); }
1750  }; // struct Iterator
1751 
1752  private:
1753  friend class Builder;
1754  friend class message2::MessageFormatter;
1755  friend class message2::Serializer;
1756 
1757  // Set to true if a copy constructor fails;
1758  // needed in order to distinguish an uninitialized
1759  // Pattern from a 0-length pattern
1760  bool bogus = false;
1761 
1762  // Possibly-empty array of parts
1763  int32_t len = 0;
1765 
1766  Pattern(const UVector& parts, UErrorCode& status);
1767  // Helper
1768  static void initParts(Pattern&, const Pattern&);
1769 
1778  int32_t numParts() const;
1789  const PatternPart& getPart(int32_t i) const;
1790 
1791  // Gets around not being able to declare Pattern::Iterator as a friend
1792  // in PatternPart
1793  static const std::variant<UnicodeString, Expression, Markup>&
1794  patternContents(const PatternPart& p) { return p.piece; }
1795  }; // class Pattern
1796 
1807  class U_I18N_API Variant : public UObject {
1808  public:
1817  const Pattern& getPattern() const { return p; }
1826  const SelectorKeys& getKeys() const { return k; }
1838  Variant(const SelectorKeys& keys, Pattern&& pattern) : k(keys), p(std::move(pattern)) {}
1847  friend inline void swap(Variant& v1, Variant& v2) noexcept {
1848  using std::swap;
1849 
1850  swap(v1.k, v2.k);
1851  swap(v1.p, v2.p);
1852  }
1859  Variant& operator=(Variant other) noexcept;
1867  Variant() = default;
1874  Variant(const Variant&);
1881  virtual ~Variant();
1882  private:
1883  /* const */ SelectorKeys k;
1884  /* const */ Pattern p;
1885  }; // class Variant
1886 
1897  class U_I18N_API Binding : public UObject {
1898  public:
1907  const Expression& getValue() const;
1916  const VariableName& getVariable() const { return var; }
1931  static Binding input(UnicodeString&& variableName, Expression&& rhs, UErrorCode& errorCode);
1941  UBool isLocal() const { return local; }
1951  Binding(const VariableName& v, Expression&& e) : var(v), expr(std::move(e)), local(true), annotation(nullptr) {}
1960  friend inline void swap(Binding& b1, Binding& b2) noexcept {
1961  using std::swap;
1962 
1963  swap(b1.var, b2.var);
1964  swap(b1.expr, b2.expr);
1965  swap(b1.local, b2.local);
1966  b1.updateAnnotation();
1967  b2.updateAnnotation();
1968  }
1975  Binding(const Binding& other);
1990  Binding() : local(true) {}
1997  virtual ~Binding();
1998  private:
1999  friend class message2::Checker;
2000  friend class message2::MessageFormatter;
2001  friend class message2::Parser;
2002  friend class message2::Serializer;
2003 
2004  /* const */ VariableName var;
2005  /* const */ Expression expr;
2006  /* const */ bool local;
2007 
2008  // The following field is always nullptr for a local
2009  // declaration, and possibly nullptr for an .input declaration
2010  // If non-null, the referent is a member of `expr` so
2011  // its lifetime is the same as the lifetime of the enclosing Binding
2012  // (as long as there's no mutation)
2013  const Operator* annotation = nullptr;
2014 
2015  const OptionMap& getOptionsInternal() const;
2016 
2017  bool hasAnnotation() const { return !local && (annotation != nullptr); }
2018  void updateAnnotation();
2019  }; // class Binding
2020 
2021  // Internal only
2022 
2023  #ifndef U_IN_DOXYGEN
2024  class U_I18N_API_CLASS Matcher : public UObject {
2025  public:
2026  U_I18N_API Matcher& operator=(Matcher);
2027  U_I18N_API Matcher(const Matcher&);
2036  U_I18N_API friend inline void swap(Matcher& m1, Matcher& m2) noexcept {
2037  using std::swap;
2038 
2039  if (m1.bogus) {
2040  m2.bogus = true;
2041  return;
2042  }
2043  if (m2.bogus) {
2044  m1.bogus = true;
2045  return;
2046  }
2047  swap(m1.selectors, m2.selectors);
2048  swap(m1.numSelectors, m2.numSelectors);
2049  swap(m1.variants, m2.variants);
2050  swap(m1.numVariants, m2.numVariants);
2051  }
2052  U_I18N_API virtual ~Matcher();
2053  private:
2054 
2055  friend class MFDataModel;
2056 
2057  Matcher(VariableName* ss, int32_t ns, Variant* vs, int32_t nv);
2058  Matcher() {}
2059 
2060  // A Matcher may have numSelectors=0 and numVariants=0
2061  // (this is a data model error, but it's representable).
2062  // So we have to keep a separate flag to track failed copies.
2063  bool bogus = false;
2064 
2065  // The variables that are being matched on.
2066  LocalArray<VariableName> selectors;
2067  // The number of selectors
2068  int32_t numSelectors = 0;
2069  // The list of `when` clauses (case arms).
2070  LocalArray<Variant> variants;
2071  // The number of variants
2072  int32_t numVariants = 0;
2073  }; // class Matcher
2074  #endif
2075 
2076  // -----------------------------------------------------------------------
2077  // Public MFDataModel class
2078 
2096  /*
2097  Classes that represent nodes in the data model are nested inside the
2098  `MFDataModel` class.
2099 
2100  Classes such as `Expression`, `Pattern` and `VariantMap` are immutable and
2101  are constructed using the builder pattern.
2102 
2103  Most classes representing nodes have copy constructors. This is because builders
2104  contain immutable data that must be copied when calling `build()`, since the builder
2105  could go out of scope before the immutable result of the builder does. Copying is
2106  also necessary to prevent unexpected mutation if intermediate builders are saved
2107  and mutated again after calling `build()`.
2108 
2109  The copy constructors perform a deep copy, for example by copying the entire
2110  list of options for an `Operator` (and copying the entire underlying vector.)
2111  Some internal fields should be `const`, but are declared as non-`const` to make
2112  the copy constructor simpler to implement. (These are noted throughout.) In
2113  other words, those fields are `const` except during the execution of a copy
2114  constructor.
2115 
2116  On the other hand, intermediate `Builder` methods that return a `Builder&`
2117  mutate the state of the builder, so in code like:
2118 
2119  Expression::Builder& exprBuilder = Expression::builder()-> setOperand(foo);
2120  Expression::Builder& exprBuilder2 = exprBuilder.setOperator(bar);
2121 
2122  the call to `setOperator()` would mutate `exprBuilder`, since `exprBuilder`
2123  and `exprBuilder2` are references to the same object.
2124 
2125  An alternate choice would be to make `build()` destructive, so that copying would
2126  be unnecessary. Or, both copying and moving variants of `build()` could be
2127  provided. Copying variants of the intermediate `Builder` methods could be
2128  provided as well, if this proved useful.
2129  */
2130  public:
2139  U_I18N_API std::vector<Binding> getLocalVariables() const {
2140  std::vector<Binding> result;
2141  if (!bogus) {
2142  return toStdVector<Binding>(bindings.getAlias(), bindingsLen);
2143  }
2144  return {};
2145  }
2154  U_I18N_API std::vector<VariableName> getSelectors() const {
2155  if (std::holds_alternative<Pattern>(body)) {
2156  return {};
2157  }
2158  const Matcher* match = std::get_if<Matcher>(&body);
2159  // match must be non-null, given the previous check
2160  return toStdVector<VariableName>(match->selectors.getAlias(), match->numSelectors);
2161  }
2170  U_I18N_API std::vector<Variant> getVariants() const {
2171  // Return empty vector if no variants
2172  if (std::holds_alternative<Pattern>(body)) {
2173  return {};
2174  }
2175  const Matcher* match = std::get_if<Matcher>(&body);
2176  // match must be non-null, given the previous check
2177  return toStdVector<Variant>(match->variants.getAlias(), match->numVariants);
2178  return {};
2179  }
2189  U_I18N_API const Pattern& getPattern() const;
2197  class U_I18N_API Builder;
2214  U_I18N_API friend inline void swap(MFDataModel& m1, MFDataModel& m2) noexcept {
2215  using std::swap;
2216 
2217  if (m1.bogus) {
2218  m2.bogus = true;
2219  return;
2220  }
2221  if (m2.bogus) {
2222  m1.bogus = true;
2223  return;
2224  }
2225  swap(m1.body, m2.body);
2226  swap(m1.bindings, m2.bindings);
2227  swap(m1.bindingsLen, m2.bindingsLen);
2228  }
2250 
2258  class U_I18N_API Builder : public UMemory {
2259  private:
2260  friend class MFDataModel;
2261 
2262  void checkDuplicate(const VariableName&, UErrorCode&) const;
2263  void buildSelectorsMessage(UErrorCode&);
2264  bool hasPattern = true;
2265  bool hasSelectors = false;
2266  Pattern pattern;
2267  // The following members are not LocalPointers for the same reason as in SelectorKeys::Builder
2268  UVector* selectors = nullptr;
2269  UVector* variants = nullptr;
2270  UVector* bindings = nullptr;
2271  public:
2296  Builder& addSelector(VariableName&& selector, UErrorCode& errorCode);
2309  Builder& addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept;
2341  MFDataModel build(UErrorCode& status) const noexcept;
2361  virtual ~Builder();
2362  Builder(const Builder&) = delete;
2363  Builder& operator=(const Builder&) = delete;
2364  Builder(Builder&&) = delete;
2365  Builder& operator=(Builder&&) = delete;
2366  }; // class Builder
2367 
2368  private:
2369  friend class message2::Checker;
2370  friend class message2::MessageFormatter;
2371  friend class message2::Serializer;
2372 
2373  Pattern empty; // Provided so that `getPattern()` can return a result
2374  // if called on a selectors message
2375  bool hasPattern() const { return std::holds_alternative<Pattern>(body); }
2376 
2377  bool bogus = false; // Set if a copy constructor fails
2378 
2379  // A message body is either a matcher (selector list and variant list),
2380  // or a single pattern
2381  std::variant<Matcher, Pattern> body;
2382 
2383  // Bindings for local variables
2384  /* const */ LocalArray<Binding> bindings;
2385  int32_t bindingsLen = 0;
2386 
2387  const Binding* getLocalVariablesInternal() const;
2388  const VariableName* getSelectorsInternal() const;
2389  const Variant* getVariantsInternal() const;
2390 
2391  int32_t numSelectors() const {
2392  const Matcher* matcher = std::get_if<Matcher>(&body);
2393  return (matcher == nullptr ? 0 : matcher->numSelectors);
2394  }
2395  int32_t numVariants() const {
2396  const Matcher* matcher = std::get_if<Matcher>(&body);
2397  return (matcher == nullptr ? 0 : matcher->numVariants);
2398  }
2399 
2400  // Helper
2401  void initBindings(const Binding*);
2402 
2403  MFDataModel(const Builder& builder, UErrorCode&) noexcept;
2404  }; // class MFDataModel
2405  } // namespace data_model
2406 } // namespace message2
2407 
2408 U_NAMESPACE_END
2409 
2410 #endif // U_HIDE_DEPRECATED_API
2411 
2412 #endif /* #if !UCONFIG_NO_MF2 */
2413 
2414 #endif /* #if !UCONFIG_NO_FORMATTING */
2415 
2416 #endif /* #if !UCONFIG_NO_NORMALIZATION */
2417 
2418 #endif /* U_SHOW_CPLUSPLUS_API */
2419 
2420 #endif // MESSAGEFORMAT_DATA_MODEL_H
2421 
2422 // eof
2423 
"Smart pointer" class, deletes objects via the C++ array delete[] operator.
Definition: localpointer.h:364
UMemory is the common ICU base class.
Definition: uobject.h:115
UObject is the common ICU "boilerplate" class.
Definition: uobject.h:222
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition: unistr.h:303
A Binding pairs a variable name with an expression.
Binding & operator=(Binding) noexcept
Copy assignment operator.
UBool isLocal() const
Returns true if and only if this binding represents a local declaration.
Binding(const Binding &other)
Copy constructor.
const Expression & getValue() const
Accesses the right-hand side of a binding.
const VariableName & getVariable() const
Accesses the left-hand side of the binding.
static Binding input(UnicodeString &&variableName, Expression &&rhs, UErrorCode &errorCode)
Constructor for input binding.
Binding(const VariableName &v, Expression &&e)
Constructor.
friend void swap(Binding &b1, Binding &b2) noexcept
Non-member swap function.
The mutable Expression::Builder class allows the operator to be constructed incrementally.
Expression build(UErrorCode &status)
Constructs a new immutable Expression using the operand and operator that were previously set.
Builder & addAttribute(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single attribute.
Builder & setOperator(Operator &&rAtor)
Sets the operator of this expression.
Builder & setOperand(Operand &&rAnd)
Sets the operand of this expression.
Builder(UErrorCode &status)
Default constructor.
The Expression class corresponds to the expression nonterminal in the MessageFormat 2 grammar and the...
U_I18N_API Expression()
Default constructor.
U_I18N_API const Operand & getOperand() const
Accesses the operand of this expression.
U_I18N_API friend void swap(Expression &e1, Expression &e2) noexcept
Non-member swap function.
U_I18N_API std::vector< Option > getAttributes() const
Gets the attributes of this expression.
U_I18N_API Expression & operator=(Expression) noexcept
Assignment operator.
virtual U_I18N_API ~Expression()
Destructor.
U_I18N_API const Operator * getOperator(UErrorCode &status) const
Accesses the function annotating this expression.
U_I18N_API UBool isStandaloneAnnotation() const
Checks if this expression is an annotation with no operand.
U_I18N_API UBool isFunctionCall() const
Checks if this expression has a function annotation (with or without an operand).
U_I18N_API Expression(const Expression &other)
Copy constructor.
The Key class corresponds to the key nonterminal in the MessageFormat 2 grammar, https://github....
U_I18N_API const Literal & asLiteral() const
Returns the contents of this key as a literal.
U_I18N_API bool operator==(const Key &other) const
Equality operator.
U_I18N_API bool operator<(const Key &other) const
Less than operator.
U_I18N_API Key & operator=(Key) noexcept
Assignment operator.
virtual U_I18N_API ~Key()
Destructor.
U_I18N_API UBool isWildcard() const
Determines if this is a wildcard key.
U_I18N_API Key(const Literal &lit)
Literal key constructor.
U_I18N_API Key(const Key &other)
Copy constructor.
U_I18N_API friend void swap(Key &k1, Key &k2) noexcept
Non-member swap function.
U_I18N_API Key()
Wildcard constructor; constructs a Key representing the catchall or wildcard key, '*'.
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.
friend void swap(Literal &l1, Literal &l2) noexcept
Non-member swap function.
Literal(UBool q, const UnicodeString &s)
Literal constructor.
const UnicodeString & unquoted() const
Returns the parsed string contents of this literal.
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 & operator=(Literal) noexcept
Assignment operator.
Literal(const Literal &other)
Copy constructor.
bool operator==(const Literal &other) const
Equality operator.
The mutable MFDataModel::Builder class allows the data model to be constructed incrementally.
Builder & addBinding(Binding &&b, UErrorCode &status)
Adds a binding, There must not already be a binding with the same name.
Builder(UErrorCode &status)
Default constructor.
Builder & addSelector(VariableName &&selector, UErrorCode &errorCode)
Adds a selector variable.
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.
The MFDataModel class describes a parsed representation of the text of a message.
U_I18N_API std::vector< Variant > getVariants() const
Accesses the variants.
U_I18N_API std::vector< VariableName > getSelectors() const
Accesses the selectors.
U_I18N_API MFDataModel(const MFDataModel &other)
Copy constructor.
virtual U_I18N_API ~MFDataModel()
Destructor.
U_I18N_API friend void swap(MFDataModel &m1, MFDataModel &m2) noexcept
Non-member swap function.
U_I18N_API std::vector< Binding > getLocalVariables() const
Accesses the local variable declarations for this data model.
U_I18N_API MFDataModel()
Default constructor.
U_I18N_API MFDataModel & operator=(MFDataModel) noexcept
Assignment operator.
The mutable Markup::Builder class allows the markup to be constructed incrementally.
Builder & setName(const UnicodeString &n)
Sets the name of this markup.
Builder & setStandalone()
Sets this to be a standalone markup.
Builder(UErrorCode &status)
Default constructor.
Builder & setOpen()
Sets this to be an opening markup.
Builder & addOption(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single option.
Builder & setClose()
Sets this to be an closing markup.
Markup build(UErrorCode &status)
Constructs a new immutable Markup using the name and type and (optionally) options and attributes tha...
Builder & addAttribute(const UnicodeString &key, Operand &&value, UErrorCode &status)
Adds a single attribute.
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.
UBool isClose() const
Checks if this markup is an closing tag.
virtual ~Markup()
Destructor.
std::vector< Option > getOptions() const
Gets the options of this markup.
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 U_I18N_API UBool isNull() const
Determines if this operand is the null operand.
U_I18N_API const UnicodeString & asVariable() const
Returns a reference to this operand's variable name.
U_I18N_API Operand(const Operand &)
Copy constructor.
U_I18N_API UBool isLiteral() const
Determines if this operand represents a literal.
U_I18N_API friend void swap(Operand &o1, Operand &o2) noexcept
Non-member swap function.
U_I18N_API Operand(const UnicodeString &v)
Variable operand constructor.
virtual U_I18N_API Operand & operator=(Operand) noexcept
Assignment operator.
U_I18N_API UBool isVariable() const
Determines if this operand represents a variable.
U_I18N_API Operand(const Literal &l)
Literal operand constructor.
U_I18N_API const Literal & asLiteral() const
Returns a reference to this operand's literal contents.
virtual U_I18N_API ~Operand()
Destructor.
U_I18N_API Operand()
Default constructor.
The mutable Operator::Builder class allows the operator to be constructed incrementally.
Operator build(UErrorCode &status)
Constructs a new immutable Operator using the function name and options that were previously set.
Builder & setFunctionName(FunctionName &&func)
Sets this operator to be a function annotation and sets its name to func.
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:/...
Operator(const Operator &other) noexcept
Copy constructor.
Operator & operator=(Operator) noexcept
Assignment operator.
friend void swap(Operator &o1, Operator &o2) noexcept
Non-member swap function.
const FunctionName & getFunctionName() const
Accesses the function name.
std::vector< Option > getOptions() const
Accesses function options.
An Option pairs an option name with an Operand.
const UnicodeString & getName() const
Accesses the left-hand side of the option.
Option & operator=(Option other) noexcept
Assignment operator.
const Operand & getValue() const
Accesses the right-hand side of the option.
Option(const Option &other)
Copy constructor.
virtual ~Option()
Destructor.
Option(const UnicodeString &n, Operand &&r)
Constructor.
friend void swap(Option &o1, Option &o2) noexcept
Non-member swap function.
A PatternPart is a single element (text or expression) in a Pattern.
U_I18N_API UBool isMarkup() const
Checks if the part is a markup part.
U_I18N_API PatternPart(const PatternPart &other)
Copy constructor.
virtual U_I18N_API ~PatternPart()
Destructor.
U_I18N_API UBool isExpression() const
Checks if the part is an expression part.
U_I18N_API PatternPart(const UnicodeString &t)
Text part constructor.
U_I18N_API const UnicodeString & asText() const
Accesses the text contents of the part.
U_I18N_API const Markup & asMarkup() const
Accesses the expression of the part.
U_I18N_API friend void swap(PatternPart &p1, PatternPart &p2) noexcept
Non-member swap function.
U_I18N_API const Expression & contents() const
Accesses the expression of the part.
U_I18N_API PatternPart(Markup &&m)
Markup part constructor.
U_I18N_API UBool isText() const
Checks if the part is a text part.
U_I18N_API PatternPart()=default
Default constructor.
U_I18N_API PatternPart(Expression &&e)
Expression part constructor.
U_I18N_API PatternPart & operator=(PatternPart) noexcept
Assignment operator.
The mutable Pattern::Builder class allows the pattern to be constructed one part at a time.
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(UnicodeString &&part, UErrorCode &status) noexcept
Adds a single text part to the pattern.
Builder & add(Expression &&part, UErrorCode &status) noexcept
Adds a single expression part to the pattern.
Builder & add(Markup &&part, UErrorCode &status) noexcept
Adds a single markup part to the pattern.
A Pattern is a sequence of formattable parts.
U_I18N_API Iterator begin() const
Returns the parts of this pattern.
U_I18N_API friend void swap(Pattern &p1, Pattern &p2) noexcept
Non-member swap function.
virtual U_I18N_API ~Pattern()
Destructor.
U_I18N_API Iterator end() const
Returns a special value to mark the end of iteration.
U_I18N_API Pattern & operator=(Pattern) noexcept
Assignment operator.
U_I18N_API Pattern(const Pattern &other)
Copy constructor.
U_I18N_API Pattern()
Default constructor.
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.
U_I18N_API SelectorKeys(const SelectorKeys &other)
Copy constructor.
U_I18N_API friend void swap(SelectorKeys &s1, SelectorKeys &s2) noexcept
Non-member swap function.
U_I18N_API SelectorKeys()
Default constructor.
U_I18N_API std::vector< Key > getKeys() const
Returns the underlying list of keys.
U_I18N_API bool operator<(const SelectorKeys &other) const
Less than operator.
U_I18N_API SelectorKeys & operator=(SelectorKeys other) noexcept
Assignment operator.
virtual U_I18N_API ~SelectorKeys()
Destructor.
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(const SelectorKeys &keys, Pattern &&pattern)
Constructor.
friend void swap(Variant &v1, Variant &v2) noexcept
Non-member swap function.
Variant & operator=(Variant other) noexcept
Assignment operator.
const SelectorKeys & getKeys() const
Accesses the keys of the variant.
Variant()=default
Default constructor.
const Pattern & getPattern() const
Accesses the pattern of the variant.
C++ API: "Smart pointers" for use with and in ICU4C C++ code.
U_COMMON_API UBool operator==(const StringPiece &x, const StringPiece &y)
Global operator == for StringPiece.
bool operator!=(const StringPiece &x, const StringPiece &y)
Global operator != for StringPiece.
Definition: stringpiece.h:346
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:269
Basic definitions for ICU, for both C and C++ APIs.
UErrorCode
Standard ICU4C error code type, a substitute for exceptions.
Definition: utypes.h:509
#define U_I18N_API_CLASS
Set to export library symbols from inside the i18n library, and to import them from outside,...
Definition: utypes.h:457
#define U_I18N_API
Set to export library symbols from inside the i18n library, and to import them from outside.
Definition: utypes.h:316