ICU 76.1  76.1
messageformat2_formattable.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 MESSAGEFORMAT2_FORMATTABLE_H
7 #define MESSAGEFORMAT2_FORMATTABLE_H
8 
9 #if U_SHOW_CPLUSPLUS_API
10 
11 #if !UCONFIG_NO_FORMATTING
12 
13 #if !UCONFIG_NO_MF2
14 
15 #include "unicode/chariter.h"
17 #include "unicode/messageformat2_data_model_names.h"
18 
19 #ifndef U_HIDE_DEPRECATED_API
20 
21 #include <map>
22 #include <variant>
23 
24 U_NAMESPACE_BEGIN
25 
26 class Hashtable;
27 class UVector;
28 
29 namespace message2 {
30 
31  class Formatter;
32  class MessageContext;
33  class Selector;
34 
35  // Formattable
36  // ----------
37 
47  public:
57  virtual const UnicodeString& tag() const = 0;
64  virtual ~FormattableObject();
65  }; // class FormattableObject
66 
67  class Formattable;
68 } // namespace message2
69 
70 U_NAMESPACE_END
71 
73 // Export an explicit template instantiation of the std::variant that is used
74 // to represent the message2::Formattable class.
75 // (When building DLLs for Windows this is required.)
76 // (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
77 // for similar examples.)
78 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
79 #if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
80 template class U_I18N_API std::_Variant_storage_<false,
81  double,
82  int64_t,
86  std::pair<const icu::message2::Formattable *,int32_t>>;
87 #endif
88 typedef std::pair<const icu::message2::Formattable*, int32_t> P;
89 template class U_I18N_API std::variant<double,
90  int64_t,
94  P>;
95 #endif
96 
98 U_NAMESPACE_BEGIN
99 
100 namespace message2 {
116  class U_I18N_API Formattable : public UObject {
117  public:
118 
125  UFormattableType getType() const;
126 
136  double getDouble(UErrorCode& status) const {
137  if (U_SUCCESS(status)) {
138  if (isDecimal() && getType() == UFMT_DOUBLE) {
139  return (std::get_if<icu::Formattable>(&contents))->getDouble();
140  }
141  if (std::holds_alternative<double>(contents)) {
142  return *(std::get_if<double>(&contents));
143  }
144  status = U_ILLEGAL_ARGUMENT_ERROR;
145  }
146  return 0;
147  }
148 
158  int32_t getLong(UErrorCode& status) const {
159  if (U_SUCCESS(status)) {
160  if (isDecimal() && getType() == UFMT_LONG) {
161  return std::get_if<icu::Formattable>(&contents)->getLong();
162  }
163  if (std::holds_alternative<int64_t>(contents)) {
164  return static_cast<int32_t>(*(std::get_if<int64_t>(&contents)));
165  }
166  status = U_ILLEGAL_ARGUMENT_ERROR;
167  }
168  return 0;
169  }
170 
181  int64_t getInt64Value(UErrorCode& status) const {
182  if (U_SUCCESS(status)) {
183  if (isDecimal() && getType() == UFMT_INT64) {
184  return std::get_if<icu::Formattable>(&contents)->getInt64();
185  }
186  if (std::holds_alternative<int64_t>(contents)) {
187  return *(std::get_if<int64_t>(&contents));
188  }
189  status = U_ILLEGAL_ARGUMENT_ERROR;
190  }
191  return 0;
192  }
193 
208  int64_t getInt64(UErrorCode& status) const;
218  const UnicodeString& getString(UErrorCode& status) const {
219  if (U_SUCCESS(status)) {
220  if (std::holds_alternative<UnicodeString>(contents)) {
221  return *std::get_if<UnicodeString>(&contents);
222  }
223  status = U_ILLEGAL_ARGUMENT_ERROR;
224  }
225  return bogusString;
226  }
227 
237  UDate getDate(UErrorCode& status) const {
238  if (U_SUCCESS(status)) {
239  if (isDate()) {
240  return *std::get_if<double>(&contents);
241  }
242  status = U_ILLEGAL_ARGUMENT_ERROR;
243  }
244  return 0;
245  }
246 
254  UBool isNumeric() const { return (getType() == UFMT_DOUBLE || getType() == UFMT_LONG || getType() == UFMT_INT64); }
255 
266  const Formattable* getArray(int32_t& count, UErrorCode& status) const;
267 
278  const FormattableObject* getObject(UErrorCode& status) const {
279  if (U_SUCCESS(status)) {
280  // Can't return a reference since FormattableObject
281  // is an abstract class
282  if (getType() == UFMT_OBJECT) {
283  return *std::get_if<const FormattableObject*>(&contents);
284  // TODO: should assert that if type is object, object is non-null
285  }
286  status = U_ILLEGAL_ARGUMENT_ERROR;
287  }
288  return nullptr;
289  }
298  friend inline void swap(Formattable& f1, Formattable& f2) noexcept {
299  using std::swap;
300 
301  swap(f1.contents, f2.contents);
302  swap(f1.holdsDate, f2.holdsDate);
303  }
310  Formattable(const Formattable&);
317  Formattable& operator=(Formattable) noexcept;
325  Formattable() : contents(0.0) {}
334  Formattable(const UnicodeString& s) : contents(s) {}
343  Formattable(double d) : contents(d) {}
352  Formattable(int64_t i) : contents(i) {}
361  Formattable f;
362  f.contents = d;
363  f.holdsDate = true;
364  return f;
365  }
380  static Formattable forDecimal(std::string_view number, UErrorCode& status);
390  Formattable(const Formattable* arr, int32_t len) : contents(std::pair(arr, len)) {}
399  Formattable(const FormattableObject* obj) : contents(obj) {}
406  virtual ~Formattable();
418  icu::Formattable asICUFormattable(UErrorCode& status) const;
419  private:
420 
421  std::variant<double,
422  int64_t,
424  icu::Formattable, // represents a Decimal
425  const FormattableObject*,
426  std::pair<const Formattable*, int32_t>> contents;
427  bool holdsDate = false; // otherwise, we get type errors about UDate being a duplicate type
428  UnicodeString bogusString; // :((((
429 
430  UBool isDecimal() const {
431  return std::holds_alternative<icu::Formattable>(contents);
432  }
433  UBool isDate() const {
434  return std::holds_alternative<double>(contents) && holdsDate;
435  }
436  }; // class Formattable
437 
451 #ifndef U_IN_DOXYGEN
452 class U_I18N_API ResolvedFunctionOption : public UObject {
453  private:
454 
455  /* const */ UnicodeString name;
456  /* const */ Formattable value;
457 
458  public:
459  const UnicodeString& getName() const { return name; }
460  const Formattable& getValue() const { return value; }
461  ResolvedFunctionOption(const UnicodeString& n, const Formattable& f) : name(n), value(f) {}
462  ResolvedFunctionOption() {}
463  ResolvedFunctionOption(ResolvedFunctionOption&&);
464  ResolvedFunctionOption& operator=(ResolvedFunctionOption&& other) noexcept {
465  name = std::move(other.name);
466  value = std::move(other.value);
467  return *this;
468  }
469  virtual ~ResolvedFunctionOption();
470 }; // class ResolvedFunctionOption
471 #endif
472 
480 using FunctionOptionsMap = std::map<UnicodeString, message2::Formattable>;
481 
489  public:
503  FunctionOptionsMap getOptions() const {
504  int32_t len;
505  const ResolvedFunctionOption* resolvedOptions = getResolvedFunctionOptions(len);
506  FunctionOptionsMap result;
507  for (int32_t i = 0; i < len; i++) {
508  const ResolvedFunctionOption& opt = resolvedOptions[i];
509  result[opt.getName()] = opt.getValue();
510  }
511  return result;
512  }
520  FunctionOptions() { options = nullptr; }
527  virtual ~FunctionOptions();
535  FunctionOptions& operator=(FunctionOptions&&) noexcept;
550  FunctionOptions& operator=(const FunctionOptions&) = delete;
551  private:
552  friend class MessageFormatter;
553  friend class StandardFunctions;
554 
555  explicit FunctionOptions(UVector&&, UErrorCode&);
556 
557  const ResolvedFunctionOption* getResolvedFunctionOptions(int32_t& len) const;
558  UBool getFunctionOption(const UnicodeString&, Formattable&) const;
559  // Returns empty string if option doesn't exist
560  UnicodeString getStringFunctionOption(const UnicodeString&) const;
561  int32_t optionsCount() const { return functionOptionsLen; }
562 
563  // Named options passed to functions
564  // This is not a Hashtable in order to make it possible for code in a public header file
565  // to construct a std::map from it, on-the-fly. Otherwise, it would be impossible to put
566  // that code in the header because it would have to call internal Hashtable methods.
567  ResolvedFunctionOption* options;
568  int32_t functionOptionsLen = 0;
569 }; // class FunctionOptions
570 
571 
572  // TODO doc comments
573  // Encapsulates either a formatted string or formatted number;
574  // more output types could be added in the future.
575 
587  public:
593  explicit FormattedValue(const UnicodeString&);
606  FormattedValue() : type(kString) {}
615  bool isString() const { return type == kString; }
624  bool isNumber() const { return type == kNumber; }
632  const UnicodeString& getString() const { return stringOutput; }
640  const number::FormattedNumber& getNumber() const { return numberOutput; }
648  FormattedValue& operator=(FormattedValue&&) noexcept;
656  FormattedValue(FormattedValue&& other) { *this = std::move(other); }
663  virtual ~FormattedValue();
664  private:
665  enum Type {
666  kString,
667  kNumber
668  };
669  Type type;
670  UnicodeString stringOutput;
671  number::FormattedNumber numberOutput;
672  }; // class FormattedValue
673 
687  public:
698  explicit FormattedPlaceholder(const UnicodeString& s) : fallback(s), type(kFallback) {}
711  : fallback(input.fallback), source(input.source),
712  formatted(std::move(output)), previousOptions(FunctionOptions()), type(kEvaluated) {}
726  : fallback(input.fallback), source(input.source),
727  formatted(std::move(output)), previousOptions(std::move(opts)), type(kEvaluated) {}
738  : fallback(fb), source(input), type(kUnevaluated) {}
746  FormattedPlaceholder() : type(kNull) {}
756  const message2::Formattable& asFormattable() const;
766  bool isFallback() const { return type == kFallback; }
776  bool isNullOperand() const { return type == kNull; }
786  bool isEvaluated() const { return (type == kEvaluated); }
795  bool canFormat() const { return !(isFallback() || isNullOperand()); }
803  const UnicodeString& getFallback() const { return fallback; }
812  const FunctionOptions& options() const { return previousOptions; }
813 
820  const FormattedValue& output() const { return formatted; }
828  FormattedPlaceholder& operator=(FormattedPlaceholder&&) noexcept;
836  FormattedPlaceholder(FormattedPlaceholder&& other) { *this = std::move(other); }
852  UnicodeString formatToString(const Locale& locale,
853  UErrorCode& status) const;
854 
855  private:
856  friend class MessageFormatter;
857 
858  enum Type {
859  kFallback, // Represents the result of formatting that encountered an error
860  kNull, // Represents the absence of both an output and an input (not necessarily an error)
861  kUnevaluated, // `source` should be valid, but there's no result yet
862  kEvaluated, // `formatted` exists
863  };
864  UnicodeString fallback;
865  Formattable source;
866  FormattedValue formatted;
867  FunctionOptions previousOptions; // Ignored unless type is kEvaluated
868  Type type;
869  }; // class FormattedPlaceholder
870 
882  public:
890  if (U_SUCCESS(status)) {
891  status = U_UNSUPPORTED_ERROR;
892  }
893  }
900  int32_t length(UErrorCode& status) const {
901  if (U_SUCCESS(status)) {
902  status = U_UNSUPPORTED_ERROR;
903  }
904  return -1;
905  }
912  char16_t charAt(int32_t index, UErrorCode& status) const {
913  (void) index;
914  if (U_SUCCESS(status)) {
915  status = U_UNSUPPORTED_ERROR;
916  }
917  return 0;
918  }
925  StringPiece subSequence(int32_t start, int32_t end, UErrorCode& status) const {
926  (void) start;
927  (void) end;
928  if (U_SUCCESS(status)) {
929  status = U_UNSUPPORTED_ERROR;
930  }
931  return "";
932  }
939  UnicodeString toString(UErrorCode& status) const override {
940  if (U_SUCCESS(status)) {
941  status = U_UNSUPPORTED_ERROR;
942  }
943  return {};
944  }
951  UnicodeString toTempString(UErrorCode& status) const override {
952  if (U_SUCCESS(status)) {
953  status = U_UNSUPPORTED_ERROR;
954  }
955  return {};
956  }
963  Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override {
964  if (U_SUCCESS(status)) {
965  status = U_UNSUPPORTED_ERROR;
966  }
967  return appendable;
968  }
975  UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override {
976  (void) cfpos;
977  if (U_SUCCESS(status)) {
978  status = U_UNSUPPORTED_ERROR;
979  }
980  return false;
981  }
989  if (U_SUCCESS(status)) {
990  status = U_UNSUPPORTED_ERROR;
991  }
992  return nullptr;
993  }
1000  virtual ~FormattedMessage();
1001  }; // class FormattedMessage
1002 
1003 } // namespace message2
1004 
1005 U_NAMESPACE_END
1006 
1007 #endif // U_HIDE_DEPRECATED_API
1008 
1009 #endif /* #if !UCONFIG_NO_MF2 */
1010 
1011 #endif /* #if !UCONFIG_NO_FORMATTING */
1012 
1013 #endif /* U_SHOW_CPLUSPLUS_API */
1014 
1015 #endif // MESSAGEFORMAT2_FORMATTABLE_H
1016 
1017 // eof
int64_t getInt64Value(UErrorCode &status) const
Gets the int64 value of this object.
FormattedMessage(UErrorCode &status)
Not yet implemented.
double getDouble(UErrorCode &status) const
Gets the double value of this object.
char16_t charAt(int32_t index, UErrorCode &status) const
Not yet implemented.
#define U_SUCCESS(x)
Does the error code indicate success?
Definition: utypes.h:742
A FormattedValue represents the result of formatting a message2::Formattable.
Formattable(const Formattable *arr, int32_t len)
Array constructor.
double UDate
Date and Time data type.
Definition: utypes.h:218
bool isNumber() const
Returns true iff this is a formatted number.
const UnicodeString & getString(UErrorCode &status) const
Gets the string value of this object.
FormattableObject is an abstract class that can be implemented in order to define an arbitrary class ...
int32_t length(UErrorCode &status) const
Not yet implemented.
bool isFallback() const
Returns true iff this is a fallback placeholder.
Formattable(const FormattableObject *obj)
Object constructor.
An abstract formatted value: a string with associated field attributes.
UFormattableType
Enum designating the type of a UFormattable instance.
Definition: uformattable.h:48
UBool isNumeric() const
Returns true if the data type of this Formattable object is kDouble.
FormattedPlaceholder(const Formattable &input, const UnicodeString &fb)
Constructor for unformatted placeholders.
UnicodeString toString(UErrorCode &status) const override
Not yet implemented.
#define U_I18N_API
Set to export library symbols from inside the i18n library, and to import them from outside...
Definition: utypes.h:316
bool isString() const
Returns true iff this is a formatted string.
CharacterIterator * toCharacterIterator(UErrorCode &status)
Not yet implemented.
Formattable(double d)
Double constructor.
Requested operation not supported in current context.
Definition: utypes.h:482
const UnicodeString & getFallback() const
Gets the fallback value of this placeholder, to be used in its place if an error occurs while formatt...
Abstract class that defines an API for iteration on text objects.
Definition: chariter.h:361
UnicodeString toTempString(UErrorCode &status) const override
Not yet implemented.
Start of codes indicating failure.
Definition: utypes.h:467
Appendable & appendTo(Appendable &appendable, UErrorCode &status) const override
Not yet implemented.
ufmt_getInt64() will return without conversion.
Definition: uformattable.h:54
ufmt_getObject() will return without conversion.
Definition: uformattable.h:55
FormattedPlaceholder(const FormattedPlaceholder &input, FormattedValue &&output)
Constructor for fully formatted placeholders.
ufmt_getLong() will return without conversion.
Definition: uformattable.h:51
bool canFormat() const
Returns true iff this represents a valid argument to the formatter.
const FormattedValue & output() const
Returns the formatted output of this placeholder.
bool isEvaluated() const
Returns true iff this has formatting output.
Formattable(int64_t i)
Int64 constructor.
Represents a span of a string containing a given field.
static Formattable forDate(UDate d)
Date factory method.
const FormattableObject * getObject(UErrorCode &status) const
Returns a pointer to the FormattableObject contained within this formattable, or if this object does ...
FormattedPlaceholder(const UnicodeString &s)
Fallback constructor.
UErrorCode
Standard ICU4C error code type, a substitute for exceptions.
Definition: utypes.h:430
FormattedPlaceholder(const FormattedPlaceholder &input, FunctionOptions &&opts, FormattedValue &&output)
Constructor for fully formatted placeholders with options.
Not yet implemented: The result of a message formatting operation.
const FunctionOptions & options() const
Returns the options of this placeholder.
const number::FormattedNumber & getNumber() const
Gets the number contents of this value.
FunctionOptionsMap getOptions() const
Returns a map of all name-value pairs provided as options to this function.
friend void swap(Formattable &f1, Formattable &f2) noexcept
Non-member swap function.
bool isNullOperand() const
Returns true iff this is a null placeholder.
The Formattable class represents a typed value that can be formatted, originating either from a messa...
Structure encapsulating named options passed to a custom selector or formatter.
int32_t getLong(UErrorCode &status) const
Gets the long value of this object.
A FormattablePlaceholder encapsulates an input value (a message2::Formattable) together with an optio...
Basic definitions for ICU, for both C and C++ APIs.
StringPiece subSequence(int32_t start, int32_t end, UErrorCode &status) const
Not yet implemented.
Formattable(const UnicodeString &s)
String constructor.
UBool nextPosition(ConstrainedFieldPosition &cfpos, UErrorCode &status) const override
Not yet implemented.
const UnicodeString & getString() const
Gets the string contents of this value.
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition: unistr.h:295
C++ API: Character Iterator.
Formattable objects can be passed to the Format class or its subclasses for formatting.
Definition: fmtable.h:63
The result of a number formatting operation.
A string-like object that points to a sized piece of memory.
Definition: stringpiece.h:61
UObject is the common ICU "boilerplate" class.
Definition: uobject.h:223
C++ API: All-in-one formatter for localized numbers, currencies, and units.
UDate getDate(UErrorCode &status) const
Gets the Date value of this object.
ufmt_getDouble() will return without conversion.
Definition: uformattable.h:50
int8_t UBool
The ICU boolean type, a signed-byte integer.
Definition: umachine.h:247
Base class for objects to which Unicode characters and strings can be appended.
Definition: appendable.h:54
A Locale object represents a specific geographical, political, or cultural region.
Definition: locid.h:195