ICU 77.1  77.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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_NORMALIZATION
12 
13 #if !UCONFIG_NO_FORMATTING
14 
15 #if !UCONFIG_NO_MF2
16 
17 #include "unicode/chariter.h"
19 #include "unicode/messageformat2_data_model_names.h"
20 
21 #ifndef U_HIDE_DEPRECATED_API
22 
23 #include <map>
24 #include <variant>
25 
26 U_NAMESPACE_BEGIN
27 
28 class Hashtable;
29 class UVector;
30 
31 namespace message2 {
32 
33  class Formatter;
34  class MessageContext;
35  class Selector;
36 
37  // Formattable
38  // ----------
39 
49  public:
59  virtual const UnicodeString& tag() const = 0;
66  virtual ~FormattableObject();
67  }; // class FormattableObject
68 
69  class Formattable;
70 } // namespace message2
71 
72 U_NAMESPACE_END
73 
75 // Export an explicit template instantiation of the std::variant that is used
76 // to represent the message2::Formattable class.
77 // (When building DLLs for Windows this is required.)
78 // (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
79 // for similar examples.)
80 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
81 #if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
82 template class U_I18N_API std::_Variant_storage_<false,
83  double,
84  int64_t,
88  std::pair<const icu::message2::Formattable *,int32_t>>;
89 #endif
90 typedef std::pair<const icu::message2::Formattable*, int32_t> P;
91 template class U_I18N_API std::variant<double,
92  int64_t,
96  P>;
97 #endif
99 
100 U_NAMESPACE_BEGIN
101 
102 namespace message2 {
118  class U_I18N_API Formattable : public UObject {
119  public:
120 
128 
138  double getDouble(UErrorCode& status) const {
139  if (U_SUCCESS(status)) {
140  if (isDecimal() && getType() == UFMT_DOUBLE) {
141  return (std::get_if<icu::Formattable>(&contents))->getDouble();
142  }
143  if (std::holds_alternative<double>(contents)) {
144  return *(std::get_if<double>(&contents));
145  }
146  status = U_ILLEGAL_ARGUMENT_ERROR;
147  }
148  return 0;
149  }
150 
160  int32_t getLong(UErrorCode& status) const {
161  if (U_SUCCESS(status)) {
162  if (isDecimal() && getType() == UFMT_LONG) {
163  return std::get_if<icu::Formattable>(&contents)->getLong();
164  }
165  if (std::holds_alternative<int64_t>(contents)) {
166  return static_cast<int32_t>(*(std::get_if<int64_t>(&contents)));
167  }
168  status = U_ILLEGAL_ARGUMENT_ERROR;
169  }
170  return 0;
171  }
172 
183  int64_t getInt64Value(UErrorCode& status) const {
184  if (U_SUCCESS(status)) {
185  if (isDecimal() && getType() == UFMT_INT64) {
186  return std::get_if<icu::Formattable>(&contents)->getInt64();
187  }
188  if (std::holds_alternative<int64_t>(contents)) {
189  return *(std::get_if<int64_t>(&contents));
190  }
191  status = U_ILLEGAL_ARGUMENT_ERROR;
192  }
193  return 0;
194  }
195 
210  int64_t getInt64(UErrorCode& status) const;
220  const UnicodeString& getString(UErrorCode& status) const {
221  if (U_SUCCESS(status)) {
222  if (std::holds_alternative<UnicodeString>(contents)) {
223  return *std::get_if<UnicodeString>(&contents);
224  }
225  status = U_ILLEGAL_ARGUMENT_ERROR;
226  }
227  return bogusString;
228  }
229 
239  UDate getDate(UErrorCode& status) const {
240  if (U_SUCCESS(status)) {
241  if (isDate()) {
242  return *std::get_if<double>(&contents);
243  }
244  status = U_ILLEGAL_ARGUMENT_ERROR;
245  }
246  return 0;
247  }
248 
256  UBool isNumeric() const { return (getType() == UFMT_DOUBLE || getType() == UFMT_LONG || getType() == UFMT_INT64); }
257 
268  const Formattable* getArray(int32_t& count, UErrorCode& status) const;
269 
280  const FormattableObject* getObject(UErrorCode& status) const {
281  if (U_SUCCESS(status)) {
282  // Can't return a reference since FormattableObject
283  // is an abstract class
284  if (getType() == UFMT_OBJECT) {
285  return *std::get_if<const FormattableObject*>(&contents);
286  // TODO: should assert that if type is object, object is non-null
287  }
288  status = U_ILLEGAL_ARGUMENT_ERROR;
289  }
290  return nullptr;
291  }
300  friend inline void swap(Formattable& f1, Formattable& f2) noexcept {
301  using std::swap;
302 
303  swap(f1.contents, f2.contents);
304  swap(f1.holdsDate, f2.holdsDate);
305  }
327  Formattable() : contents(0.0) {}
336  Formattable(const UnicodeString& s) : contents(s) {}
345  Formattable(double d) : contents(d) {}
354  Formattable(int64_t i) : contents(i) {}
363  Formattable f;
364  f.contents = d;
365  f.holdsDate = true;
366  return f;
367  }
382  static Formattable forDecimal(std::string_view number, UErrorCode& status);
392  Formattable(const Formattable* arr, int32_t len) : contents(std::pair(arr, len)) {}
401  Formattable(const FormattableObject* obj) : contents(obj) {}
408  virtual ~Formattable();
421  private:
422 
423  std::variant<double,
424  int64_t,
426  icu::Formattable, // represents a Decimal
427  const FormattableObject*,
428  std::pair<const Formattable*, int32_t>> contents;
429  bool holdsDate = false; // otherwise, we get type errors about UDate being a duplicate type
430  UnicodeString bogusString; // :((((
431 
432  UBool isDecimal() const {
433  return std::holds_alternative<icu::Formattable>(contents);
434  }
435  UBool isDate() const {
436  return std::holds_alternative<double>(contents) && holdsDate;
437  }
438  }; // class Formattable
439 
453 #ifndef U_IN_DOXYGEN
454 class U_I18N_API ResolvedFunctionOption : public UObject {
455  private:
456 
457  /* const */ UnicodeString name;
458  /* const */ Formattable value;
459 
460  public:
461  const UnicodeString& getName() const { return name; }
462  const Formattable& getValue() const { return value; }
463  ResolvedFunctionOption(const UnicodeString& n, const Formattable& f) : name(n), value(f) {}
464  ResolvedFunctionOption() {}
465  ResolvedFunctionOption(ResolvedFunctionOption&&);
466  ResolvedFunctionOption& operator=(ResolvedFunctionOption&& other) noexcept {
467  name = std::move(other.name);
468  value = std::move(other.value);
469  return *this;
470  }
471  virtual ~ResolvedFunctionOption();
472 }; // class ResolvedFunctionOption
473 #endif
474 
482 using FunctionOptionsMap = std::map<UnicodeString, message2::Formattable>;
483 
491  public:
505  FunctionOptionsMap getOptions() const {
506  int32_t len;
507  const ResolvedFunctionOption* resolvedOptions = getResolvedFunctionOptions(len);
508  FunctionOptionsMap result;
509  for (int32_t i = 0; i < len; i++) {
510  const ResolvedFunctionOption& opt = resolvedOptions[i];
511  result[opt.getName()] = opt.getValue();
512  }
513  return result;
514  }
522  FunctionOptions() { options = nullptr; }
529  virtual ~FunctionOptions();
552  FunctionOptions& operator=(const FunctionOptions&) = delete;
553  private:
554  friend class InternalValue;
555  friend class MessageFormatter;
556  friend class StandardFunctions;
557 
558  explicit FunctionOptions(UVector&&, UErrorCode&);
559 
560  const ResolvedFunctionOption* getResolvedFunctionOptions(int32_t& len) const;
561  UBool getFunctionOption(const UnicodeString&, Formattable&) const;
562  // Returns empty string if option doesn't exist
563  UnicodeString getStringFunctionOption(const UnicodeString&) const;
564  int32_t optionsCount() const { return functionOptionsLen; }
565 
566  // Named options passed to functions
567  // This is not a Hashtable in order to make it possible for code in a public header file
568  // to construct a std::map from it, on-the-fly. Otherwise, it would be impossible to put
569  // that code in the header because it would have to call internal Hashtable methods.
570  ResolvedFunctionOption* options;
571  int32_t functionOptionsLen = 0;
572 
573  // Returns a new FunctionOptions
574  FunctionOptions mergeOptions(FunctionOptions&& other, UErrorCode&);
575 }; // class FunctionOptions
576 
588  public:
594  explicit FormattedValue(const UnicodeString&);
607  FormattedValue() : type(kString) {}
616  bool isString() const { return type == kString; }
625  bool isNumber() const { return type == kNumber; }
633  const UnicodeString& getString() const { return stringOutput; }
641  const number::FormattedNumber& getNumber() const { return numberOutput; }
657  FormattedValue(FormattedValue&& other) { *this = std::move(other); }
664  virtual ~FormattedValue();
665  private:
666  enum Type {
667  kString,
668  kNumber
669  };
670  Type type;
671  UnicodeString stringOutput;
672  number::FormattedNumber numberOutput;
673  }; // class FormattedValue
674 
688  public:
699  explicit FormattedPlaceholder(const UnicodeString& s) : fallback(s), type(kFallback) {}
712  : fallback(input.fallback), source(input.source),
713  formatted(std::move(output)), previousOptions(FunctionOptions()), type(kEvaluated) {}
727  : fallback(input.fallback), source(input.source),
728  formatted(std::move(output)), previousOptions(std::move(opts)), type(kEvaluated) {}
739  : fallback(fb), source(input), type(kUnevaluated) {}
747  FormattedPlaceholder() : type(kNull) {}
767  bool isFallback() const { return type == kFallback; }
777  bool isNullOperand() const { return type == kNull; }
787  bool isEvaluated() const { return (type == kEvaluated); }
796  bool canFormat() const { return !(isFallback() || isNullOperand()); }
804  const UnicodeString& getFallback() const { return fallback; }
813  const FunctionOptions& options() const { return previousOptions; }
814 
821  const FormattedValue& output() const { return formatted; }
837  FormattedPlaceholder(FormattedPlaceholder&& other) { *this = std::move(other); }
854  UErrorCode& status) const;
855 
856  private:
857  friend class MessageFormatter;
858 
859  enum Type {
860  kFallback, // Represents the result of formatting that encountered an error
861  kNull, // Represents the absence of both an output and an input (not necessarily an error)
862  kUnevaluated, // `source` should be valid, but there's no result yet
863  kEvaluated, // `formatted` exists
864  };
865  UnicodeString fallback;
866  Formattable source;
867  FormattedValue formatted;
868  FunctionOptions previousOptions; // Ignored unless type is kEvaluated
869  Type type;
870  }; // class FormattedPlaceholder
871 
883  public:
891  if (U_SUCCESS(status)) {
892  status = U_UNSUPPORTED_ERROR;
893  }
894  }
901  int32_t length(UErrorCode& status) const {
902  if (U_SUCCESS(status)) {
903  status = U_UNSUPPORTED_ERROR;
904  }
905  return -1;
906  }
913  char16_t charAt(int32_t index, UErrorCode& status) const {
914  (void) index;
915  if (U_SUCCESS(status)) {
916  status = U_UNSUPPORTED_ERROR;
917  }
918  return 0;
919  }
926  StringPiece subSequence(int32_t start, int32_t end, UErrorCode& status) const {
927  (void) start;
928  (void) end;
929  if (U_SUCCESS(status)) {
930  status = U_UNSUPPORTED_ERROR;
931  }
932  return "";
933  }
940  UnicodeString toString(UErrorCode& status) const override {
941  if (U_SUCCESS(status)) {
942  status = U_UNSUPPORTED_ERROR;
943  }
944  return {};
945  }
952  UnicodeString toTempString(UErrorCode& status) const override {
953  if (U_SUCCESS(status)) {
954  status = U_UNSUPPORTED_ERROR;
955  }
956  return {};
957  }
964  Appendable& appendTo(Appendable& appendable, UErrorCode& status) const override {
965  if (U_SUCCESS(status)) {
966  status = U_UNSUPPORTED_ERROR;
967  }
968  return appendable;
969  }
976  UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override {
977  (void) cfpos;
978  if (U_SUCCESS(status)) {
979  status = U_UNSUPPORTED_ERROR;
980  }
981  return false;
982  }
990  if (U_SUCCESS(status)) {
991  status = U_UNSUPPORTED_ERROR;
992  }
993  return nullptr;
994  }
1002  }; // class FormattedMessage
1003 
1004 } // namespace message2
1005 
1006 U_NAMESPACE_END
1007 
1008 #endif // U_HIDE_DEPRECATED_API
1009 
1010 #endif /* #if !UCONFIG_NO_MF2 */
1011 
1012 #endif /* #if !UCONFIG_NO_FORMATTING */
1013 
1014 #endif /* #if !UCONFIG_NO_NORMALIZATION */
1015 
1016 #endif /* U_SHOW_CPLUSPLUS_API */
1017 
1018 #endif // MESSAGEFORMAT2_FORMATTABLE_H
1019 
1020 // eof
C++ API: Character Iterator.
Base class for objects to which Unicode characters and strings can be appended.
Definition: appendable.h:54
Abstract class that defines an API for iteration on text objects.
Definition: chariter.h:361
Represents a span of a string containing a given field.
Formattable objects can be passed to the Format class or its subclasses for formatting.
Definition: fmtable.h:63
An abstract formatted value: a string with associated field attributes.
A Locale object represents a specific geographical, political, or cultural region.
Definition: locid.h:195
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
UnicodeString is a string class that stores Unicode characters directly and provides similar function...
Definition: unistr.h:296
FormattableObject is an abstract class that can be implemented in order to define an arbitrary class ...
virtual ~FormattableObject()
Destructor.
virtual const UnicodeString & tag() const =0
Returns an arbitrary string representing the type of this object.
The Formattable class represents a typed value that can be formatted, originating either from a messa...
Formattable(const FormattableObject *obj)
Object constructor.
Formattable(const UnicodeString &s)
String constructor.
const FormattableObject * getObject(UErrorCode &status) const
Returns a pointer to the FormattableObject contained within this formattable, or if this object does ...
Formattable(const Formattable *arr, int32_t len)
Array constructor.
Formattable(int64_t i)
Int64 constructor.
static Formattable forDecimal(std::string_view number, UErrorCode &status)
Creates a Formattable object of an appropriate numeric type from a a decimal number in string form.
double getDouble(UErrorCode &status) const
Gets the double value of this object.
icu::Formattable asICUFormattable(UErrorCode &status) const
Converts the Formattable object to an ICU Formattable object.
virtual ~Formattable()
Destructor.
const UnicodeString & getString(UErrorCode &status) const
Gets the string value of this object.
int64_t getInt64(UErrorCode &status) const
Gets the int64 value of this object.
int32_t getLong(UErrorCode &status) const
Gets the long value of this object.
int64_t getInt64Value(UErrorCode &status) const
Gets the int64 value of this object.
const Formattable * getArray(int32_t &count, UErrorCode &status) const
Gets the array value and count of this object.
UBool isNumeric() const
Returns true if the data type of this Formattable object is kDouble.
static Formattable forDate(UDate d)
Date factory method.
Formattable(double d)
Double constructor.
friend void swap(Formattable &f1, Formattable &f2) noexcept
Non-member swap function.
Formattable(const Formattable &)
Copy constructor.
UFormattableType getType() const
Gets the data type of this Formattable object.
UDate getDate(UErrorCode &status) const
Gets the Date value of this object.
Formattable & operator=(Formattable) noexcept
Assignment operator.
Not yet implemented: The result of a message formatting operation.
UBool nextPosition(ConstrainedFieldPosition &cfpos, UErrorCode &status) const override
Not yet implemented.
StringPiece subSequence(int32_t start, int32_t end, UErrorCode &status) const
Not yet implemented.
int32_t length(UErrorCode &status) const
Not yet implemented.
CharacterIterator * toCharacterIterator(UErrorCode &status)
Not yet implemented.
UnicodeString toTempString(UErrorCode &status) const override
Not yet implemented.
FormattedMessage(UErrorCode &status)
Not yet implemented.
UnicodeString toString(UErrorCode &status) const override
Not yet implemented.
Appendable & appendTo(Appendable &appendable, UErrorCode &status) const override
Not yet implemented.
virtual ~FormattedMessage()
Destructor.
char16_t charAt(int32_t index, UErrorCode &status) const
Not yet implemented.
A FormattablePlaceholder encapsulates an input value (a message2::Formattable) together with an optio...
const UnicodeString & getFallback() const
Gets the fallback value of this placeholder, to be used in its place if an error occurs while formatt...
FormattedPlaceholder(const UnicodeString &s)
Fallback constructor.
UnicodeString formatToString(const Locale &locale, UErrorCode &status) const
Formats this as a string, using defaults.
bool isEvaluated() const
Returns true iff this has formatting output.
bool isNullOperand() const
Returns true iff this is a null placeholder.
FormattedPlaceholder(const FormattedPlaceholder &input, FormattedValue &&output)
Constructor for fully formatted placeholders.
FormattedPlaceholder & operator=(FormattedPlaceholder &&) noexcept
Move assignment operator: The source FormattedPlaceholder will be left in a valid but undefined state...
bool isFallback() const
Returns true iff this is a fallback placeholder.
const FunctionOptions & options() const
Returns the options of this placeholder.
FormattedPlaceholder(const Formattable &input, const UnicodeString &fb)
Constructor for unformatted placeholders.
bool canFormat() const
Returns true iff this represents a valid argument to the formatter.
FormattedPlaceholder(const FormattedPlaceholder &input, FunctionOptions &&opts, FormattedValue &&output)
Constructor for fully formatted placeholders with options.
const FormattedValue & output() const
Returns the formatted output of this placeholder.
const message2::Formattable & asFormattable() const
Returns the source Formattable value for this placeholder.
A FormattedValue represents the result of formatting a message2::Formattable.
const UnicodeString & getString() const
Gets the string contents of this value.
virtual ~FormattedValue()
Destructor.
FormattedValue(number::FormattedNumber &&)
Formatted number constructor.
const number::FormattedNumber & getNumber() const
Gets the number contents of this value.
bool isNumber() const
Returns true iff this is a formatted number.
FormattedValue(const UnicodeString &)
Formatted string constructor.
FormattedValue & operator=(FormattedValue &&) noexcept
Move assignment operator: The source FormattedValue will be left in a valid but undefined state.
bool isString() const
Returns true iff this is a formatted string.
Structure encapsulating named options passed to a custom selector or formatter.
virtual ~FunctionOptions()
Destructor.
FunctionOptions & operator=(FunctionOptions &&) noexcept
Move assignment operator: The source FunctionOptions will be left in a valid but undefined state.
FunctionOptionsMap getOptions() const
Returns a map of all name-value pairs provided as options to this function.
The result of a number formatting operation.
C++ API: All-in-one formatter for localized numbers, currencies, and units.
UFormattableType
Enum designating the type of a UFormattable instance.
Definition: uformattable.h:48
@ UFMT_LONG
ufmt_getLong() will return without conversion.
Definition: uformattable.h:51
@ UFMT_OBJECT
ufmt_getObject() will return without conversion.
Definition: uformattable.h:55
@ UFMT_DOUBLE
ufmt_getDouble() will return without conversion.
Definition: uformattable.h:50
@ UFMT_INT64
ufmt_getInt64() will return without conversion.
Definition: uformattable.h:54
int8_t UBool
The ICU boolean type, a signed-byte integer.
Definition: umachine.h:247
Basic definitions for ICU, for both C and C++ APIs.
UErrorCode
Standard ICU4C error code type, a substitute for exceptions.
Definition: utypes.h:430
@ U_ILLEGAL_ARGUMENT_ERROR
Start of codes indicating failure.
Definition: utypes.h:467
@ U_UNSUPPORTED_ERROR
Requested operation not supported in current context.
Definition: utypes.h:482
#define U_SUCCESS(x)
Does the error code indicate success?
Definition: utypes.h:743
#define U_I18N_API
Set to export library symbols from inside the i18n library, and to import them from outside.
Definition: utypes.h:316
double UDate
Date and Time data type.
Definition: utypes.h:218