ICU 76.1  76.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_FORMATTING
12 
13 #if !UCONFIG_NO_MF2
14 
15 #include "unicode/localpointer.h"
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 
27 U_NAMESPACE_BEGIN
28 
29 class 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
36 template<typename T>
37 static 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 
52 namespace 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:
86  UnicodeString quoted() const;
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  }
145  Literal& operator=(Literal) noexcept;
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
208 template class U_I18N_API LocalPointerBase<message2::data_model::Literal>;
209 template class U_I18N_API LocalArray<message2::data_model::Literal>;
210 #endif
211 #if defined(U_REAL_MSVC)
212 #pragma warning(pop)
213 #endif
214 
216 U_NAMESPACE_END
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)
226 struct U_I18N_API std::_Nontrivial_dummy_type;
227 template class U_I18N_API std::_Variant_storage_<false, icu::UnicodeString, icu::message2::data_model::Literal>;
228 #endif
229 template class U_I18N_API std::variant<icu::UnicodeString, icu::message2::data_model::Literal>;
230 template class U_I18N_API std::optional<std::variant<icu::UnicodeString, icu::message2::data_model::Literal>>;
231 template class U_I18N_API std::optional<icu::message2::data_model::Literal>;
232 #endif
233 
235 U_NAMESPACE_BEGIN
236 
237 namespace 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
499 template class U_I18N_API LocalPointerBase<message2::data_model::Key>;
500 template class U_I18N_API LocalArray<message2::data_model::Key>;
501 #endif
502 
504 namespace 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;
580  Builder(UErrorCode& status);
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)) {}
717  Option() {}
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  }
738  Option(const Option& other);
745  Option& operator=(Option other) noexcept;
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
767 template class U_I18N_API LocalPointerBase<message2::data_model::Option>;
768 template class U_I18N_API LocalArray<message2::data_model::Option>;
769 #endif
770 
772 namespace 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 
833 U_NAMESPACE_END
834 
835 U_NAMESPACE_BEGIN
836 
837 namespace 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:
899  Builder& setFunctionName(FunctionName&& func);
912  Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status) noexcept;
928  Operator build(UErrorCode& status);
938  Builder(UErrorCode& status);
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 
1013 U_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
1022 template class U_I18N_API std::optional<icu::message2::data_model::Operator>;
1023 #endif
1024 
1026 U_NAMESPACE_BEGIN
1027 
1028 namespace 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(); }
1111  Markup() {}
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; }
1185  Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status);
1197  Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1215  Markup build(UErrorCode& status);
1225  Builder(UErrorCode& status);
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 
1265  class U_I18N_API Expression : public UObject {
1266  public:
1277  UBool isStandaloneAnnotation() const;
1288  UBool isFunctionCall() const;
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:
1350  Builder& setOperand(Operand&& rAnd);
1360  Builder& setOperator(Operator&& rAtor);
1372  Builder& addAttribute(const UnicodeString &key, Operand&& value, UErrorCode& status);
1390  Expression build(UErrorCode& status);
1400  Builder(UErrorCode& status);
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  }
1434  Expression(const Expression& other);
1441  Expression& operator=(Expression) noexcept;
1449  Expression();
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
1492 template class U_I18N_API LocalPointerBase<message2::data_model::Expression>;
1493 template class U_I18N_API LocalArray<message2::data_model::Expression>;
1494 #endif
1495 
1497 namespace 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  }
1591  PatternPart(const PatternPart& other);
1598  PatternPart& operator=(PatternPart) noexcept;
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
1659 template class U_I18N_API LocalPointerBase<message2::data_model::PatternPart>;
1660 template class U_I18N_API LocalArray<message2::data_model::PatternPart>;
1661 #endif
1662 
1664 namespace 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:
1732  Builder& add(Expression&& part, UErrorCode& status) noexcept;
1743  Builder& add(Markup&& part, UErrorCode& status) noexcept;
1754  Builder& add(UnicodeString&& part, UErrorCode& status) noexcept;
1767  Pattern build(UErrorCode& status) const noexcept;
1777  Builder(UErrorCode& status);
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
2165 template class U_I18N_API LocalPointerBase<message2::data_model::Variant>;
2166 template class U_I18N_API LocalPointerBase<message2::data_model::Binding>;
2167 template class U_I18N_API LocalArray<message2::data_model::Variant>;
2168 template class U_I18N_API LocalArray<message2::data_model::Binding>;
2169 #endif
2170 
2172 namespace 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 
2234 U_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)
2244 template class U_I18N_API std::_Variant_storage_<false, icu::message2::Matcher,icu::message2::data_model::Pattern>;
2245 #endif
2246 template class U_I18N_API std::variant<icu::message2::Matcher,icu::message2::data_model::Pattern>;
2247 #endif
2248 
2250 U_NAMESPACE_BEGIN
2251 
2252 namespace 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 
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:
2463  Builder& addBinding(Binding&& b, UErrorCode& status);
2475  Builder& addSelector(Expression&& selector, UErrorCode& errorCode) noexcept;
2488  Builder& addVariant(SelectorKeys&& keys, Pattern&& pattern, UErrorCode& errorCode) noexcept;
2500  Builder& setPattern(Pattern&& pattern);
2520  MFDataModel build(UErrorCode& status) const noexcept;
2533  Builder(UErrorCode& status);
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 
2587 U_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 
const SelectorKeys & getKeys() const
Accesses the keys of the variant.
friend void swap(SelectorKeys &s1, SelectorKeys &s2) noexcept
Non-member swap function.
The mutable Markup::Builder class allows the markup to be constructed incrementally.
std::vector< Option > getAttributes() const
Gets the attributes of this expression.
A Variant pairs a list of keys with a pattern It corresponds to the Variant interface defined in http...
std::vector< Option > getAttributes() const
Gets the attributes of this markup.
A PatternPart is a single element (text or expression) in a Pattern.
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.
UBool isText() const
Checks if the part is a text part.
Builder & setName(const UnicodeString &n)
Sets the name of this markup.
Literal(const Literal &other)
Copy constructor.
std::vector< Variant > getVariants() const
Accesses the variants.
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.
Iterator end() const
Returns a special value to mark the end of iteration.
const UnicodeString & getName() const
Accesses the left-hand side of the option.
friend void swap(Literal &l1, Literal &l2) noexcept
Non-member swap function.
std::vector< Key > getKeys() const
Returns the underlying list of keys.
UBool isStandalone() const
Checks if this markup is an standalone tag.
Iterator begin() const
Returns the parts of this pattern.
UBool isQuoted() const
Determines if this literal appeared as a quoted literal in the message.
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.
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.
const std::vector< Expression > getSelectors() const
Accesses the selectors.
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.
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 ...
Key(const Key &other)
Copy constructor.
C++ API: "Smart pointers" for use with and in ICU4C C++ code.
The MFDataModel class describes a parsed representation of the text of a message. ...
friend void swap(Option &o1, Option &o2) noexcept
Non-member swap function.
friend void swap(Binding &b1, Binding &b2) noexcept
Non-member swap function.
"Smart pointer" class, deletes objects via the C++ array delete[] operator.
Definition: localpointer.h:366
std::vector< Option > getOptions() const
Gets the options of this markup.
reference operator*() const
Dereference operator (gets the element at the current iterator position)
UBool isExpression() const
Checks if the part is an expression part.
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.
PatternPart(const UnicodeString &t)
Text part constructor.
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.
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 .
UBool isMarkup() const
Checks if the part is a markup part.
UBool isOpen() const
Checks if this markup is an opening tag.
UBool isLocal() const
Returns true if and only if this binding represents a local declaration.
Operand(const UnicodeString &v)
Variable operand constructor.
Basic definitions for ICU, for both C and C++ APIs.
UBool isWildcard() const
Determines if this is a wildcard key.
std::vector< Option > getOptions() const
Accesses function options.
A Pattern is a sequence of formattable parts.
const Pattern & getPattern() const
Accesses the pattern of the variant.
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition: unistr.h:295
The SelectorKeys class represents the key list for a single variant.
friend void swap(PatternPart &p1, PatternPart &p2) noexcept
Non-member swap function.
const VariableName & getVariable() const
Accesses the left-hand side of the binding.
UObject is the common ICU "boilerplate" class.
Definition: uobject.h:223
const UnicodeString & getName() const
Gets the name of this markup.
UMemory is the common ICU base class.
Definition: uobject.h:115
Builder & setStandalone()
Sets this to be a standalone markup.
std::vector< Binding > getLocalVariables() const
Accesses the local variable declarations for this data model.
friend void swap(Operand &o1, Operand &o2) noexcept
Non-member swap function.
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.
UBool isClose() const
Checks if this markup is an closing tag.
const Operand & getValue() const
Accesses the right-hand side of the option.
The mutable Operator::Builder class allows the operator to be constructed incrementally.