ICU 77.1  77.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_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
98 
100 U_NAMESPACE_BEGIN
101 
102 namespace message2 {
118  class U_I18N_API Formattable : public UObject {
119  public:
120 
127  UFormattableType getType() const;
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  }
312  Formattable(const Formattable&);
319  Formattable& operator=(Formattable) noexcept;
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();
420  icu::Formattable asICUFormattable(UErrorCode& status) const;
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();
537  FunctionOptions& operator=(FunctionOptions&&) noexcept;
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; }
649  FormattedValue& operator=(FormattedValue&&) noexcept;
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) {}
757  const message2::Formattable& asFormattable() const;
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; }
829  FormattedPlaceholder& operator=(FormattedPlaceholder&&) noexcept;
837  FormattedPlaceholder(FormattedPlaceholder&& other) { *this = std::move(other); }
853  UnicodeString formatToString(const Locale& locale,
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  }
1001  virtual ~FormattedMessage();
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
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:743
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