1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 03/25/97 clhuang Initial Implementation.
15 ********************************************************************************
18 #include "unicode/utypes.h"
20 #if !UCONFIG_NO_FORMATTING
24 #include "unicode/fmtable.h"
25 #include "unicode/ustring.h"
26 #include "unicode/measure.h"
27 #include "unicode/curramt.h"
28 #include "unicode/uformattable.h"
32 #include "fmtableimp.h"
33 #include "number_decimalquantity.h"
35 // *****************************************************************************
37 // *****************************************************************************
41 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable
)
43 using number::impl::DecimalQuantity
;
46 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
48 // NOTE: As of 3.0, there are limitations to the UObject API. It does
49 // not (yet) support cloning, operator=, nor operator==. To
50 // work around this, I implement some simple inlines here. Later
51 // these can be modified or removed. [alan]
53 // NOTE: These inlines assume that all fObjects are in fact instances
54 // of the Measure class, which is true as of 3.0. [alan]
56 // Return TRUE if *a == *b.
57 static inline UBool
objectEquals(const UObject
* a
, const UObject
* b
) {
58 // LATER: return *a == *b;
59 return *((const Measure
*) a
) == *((const Measure
*) b
);
62 // Return a clone of *a.
63 static inline UObject
* objectClone(const UObject
* a
) {
64 // LATER: return a->clone();
65 return ((const Measure
*) a
)->clone();
68 // Return TRUE if *a is an instance of Measure.
69 static inline UBool
instanceOfMeasure(const UObject
* a
) {
70 return dynamic_cast<const Measure
*>(a
) != NULL
;
74 * Creates a new Formattable array and copies the values from the specified
76 * @param array the original array
77 * @param count the original array count
78 * @return the new Formattable array.
80 static Formattable
* createArrayCopy(const Formattable
* array
, int32_t count
) {
81 Formattable
*result
= new Formattable
[count
];
83 for (int32_t i
=0; i
<count
; ++i
)
84 result
[i
] = array
[i
]; // Don't memcpy!
89 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
92 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
94 static void setError(UErrorCode
& ec
, UErrorCode err
) {
101 // Common initialization code, shared by constructors.
102 // Put everything into a known state.
104 void Formattable::init() {
108 fDecimalQuantity
= NULL
;
112 // -------------------------------------
113 // default constructor.
114 // Creates a formattable object with a long value 0.
116 Formattable::Formattable() {
120 // -------------------------------------
121 // Creates a formattable object with a Date instance.
123 Formattable::Formattable(UDate date
, ISDATE
/*isDate*/)
130 // -------------------------------------
131 // Creates a formattable object with a double value.
133 Formattable::Formattable(double value
)
137 fValue
.fDouble
= value
;
140 // -------------------------------------
141 // Creates a formattable object with an int32_t value.
143 Formattable::Formattable(int32_t value
)
146 fValue
.fInt64
= value
;
149 // -------------------------------------
150 // Creates a formattable object with an int64_t value.
152 Formattable::Formattable(int64_t value
)
156 fValue
.fInt64
= value
;
159 // -------------------------------------
160 // Creates a formattable object with a decimal number value from a string.
162 Formattable::Formattable(StringPiece number
, UErrorCode
&status
) {
164 setDecimalNumber(number
, status
);
168 // -------------------------------------
169 // Creates a formattable object with a UnicodeString instance.
171 Formattable::Formattable(const UnicodeString
& stringToCopy
)
175 fValue
.fString
= new UnicodeString(stringToCopy
);
178 // -------------------------------------
179 // Creates a formattable object with a UnicodeString* value.
180 // (adopting symantics)
182 Formattable::Formattable(UnicodeString
* stringToAdopt
)
186 fValue
.fString
= stringToAdopt
;
189 Formattable::Formattable(UObject
* objectToAdopt
)
193 fValue
.fObject
= objectToAdopt
;
196 // -------------------------------------
198 Formattable::Formattable(const Formattable
* arrayToCopy
, int32_t count
)
199 : UObject(), fType(kArray
)
203 fValue
.fArrayAndCount
.fArray
= createArrayCopy(arrayToCopy
, count
);
204 fValue
.fArrayAndCount
.fCount
= count
;
207 // -------------------------------------
211 Formattable::Formattable(const Formattable
&source
)
218 // -------------------------------------
219 // assignment operator
222 Formattable::operator=(const Formattable
& source
)
226 // Disposes the current formattable value/setting.
229 // Sets the correct data type for this value.
230 fType
= source
.fType
;
234 // Sets each element in the array one by one and records the array count.
235 fValue
.fArrayAndCount
.fCount
= source
.fValue
.fArrayAndCount
.fCount
;
236 fValue
.fArrayAndCount
.fArray
= createArrayCopy(source
.fValue
.fArrayAndCount
.fArray
,
237 source
.fValue
.fArrayAndCount
.fCount
);
240 // Sets the string value.
241 fValue
.fString
= new UnicodeString(*source
.fValue
.fString
);
244 // Sets the double value.
245 fValue
.fDouble
= source
.fValue
.fDouble
;
249 // Sets the long value.
250 fValue
.fInt64
= source
.fValue
.fInt64
;
253 // Sets the Date value.
254 fValue
.fDate
= source
.fValue
.fDate
;
257 fValue
.fObject
= objectClone(source
.fValue
.fObject
);
261 UErrorCode status
= U_ZERO_ERROR
;
262 if (source
.fDecimalQuantity
!= NULL
) {
263 fDecimalQuantity
= new DecimalQuantity(*source
.fDecimalQuantity
);
265 if (source
.fDecimalStr
!= NULL
) {
266 fDecimalStr
= new CharString(*source
.fDecimalStr
, status
);
267 if (U_FAILURE(status
)) {
276 // -------------------------------------
279 Formattable::operator==(const Formattable
& that
) const
283 if (this == &that
) return TRUE
;
285 // Returns FALSE if the data types are different.
286 if (fType
!= that
.fType
) return FALSE
;
288 // Compares the actual data values.
292 equal
= (fValue
.fDate
== that
.fValue
.fDate
);
295 equal
= (fValue
.fDouble
== that
.fValue
.fDouble
);
299 equal
= (fValue
.fInt64
== that
.fValue
.fInt64
);
302 equal
= (*(fValue
.fString
) == *(that
.fValue
.fString
));
305 if (fValue
.fArrayAndCount
.fCount
!= that
.fValue
.fArrayAndCount
.fCount
) {
309 // Checks each element for equality.
310 for (i
=0; i
<fValue
.fArrayAndCount
.fCount
; ++i
) {
311 if (fValue
.fArrayAndCount
.fArray
[i
] != that
.fValue
.fArrayAndCount
.fArray
[i
]) {
318 if (fValue
.fObject
== NULL
|| that
.fValue
.fObject
== NULL
) {
321 equal
= objectEquals(fValue
.fObject
, that
.fValue
.fObject
);
326 // TODO: compare digit lists if numeric.
330 // -------------------------------------
332 Formattable::~Formattable()
337 // -------------------------------------
339 void Formattable::dispose()
341 // Deletes the data value if necessary.
344 delete fValue
.fString
;
347 delete[] fValue
.fArrayAndCount
.fArray
;
350 delete fValue
.fObject
;
362 delete fDecimalQuantity
;
363 fDecimalQuantity
= NULL
;
367 Formattable::clone() const {
368 return new Formattable(*this);
371 // -------------------------------------
372 // Gets the data type of this Formattable object.
374 Formattable::getType() const
380 Formattable::isNumeric() const {
391 // -------------------------------------
393 //Formattable::getLong(UErrorCode* status) const
394 Formattable::getLong(UErrorCode
& status
) const
396 if (U_FAILURE(status
)) {
401 case Formattable::kLong
:
402 return (int32_t)fValue
.fInt64
;
403 case Formattable::kInt64
:
404 if (fValue
.fInt64
> INT32_MAX
) {
405 status
= U_INVALID_FORMAT_ERROR
;
407 } else if (fValue
.fInt64
< INT32_MIN
) {
408 status
= U_INVALID_FORMAT_ERROR
;
411 return (int32_t)fValue
.fInt64
;
413 case Formattable::kDouble
:
414 if (fValue
.fDouble
> INT32_MAX
) {
415 status
= U_INVALID_FORMAT_ERROR
;
417 } else if (fValue
.fDouble
< INT32_MIN
) {
418 status
= U_INVALID_FORMAT_ERROR
;
421 return (int32_t)fValue
.fDouble
; // loses fraction
423 case Formattable::kObject
:
424 if (fValue
.fObject
== NULL
) {
425 status
= U_MEMORY_ALLOCATION_ERROR
;
428 // TODO Later replace this with instanceof call
429 if (instanceOfMeasure(fValue
.fObject
)) {
430 return ((const Measure
*) fValue
.fObject
)->
431 getNumber().getLong(status
);
435 status
= U_INVALID_FORMAT_ERROR
;
440 // -------------------------------------
441 // Maximum int that can be represented exactly in a double. (53 bits)
442 // Larger ints may be rounded to a near-by value as not all are representable.
443 // TODO: move this constant elsewhere, possibly configure it for different
444 // floating point formats, if any non-standard ones are still in use.
445 static const int64_t U_DOUBLE_MAX_EXACT_INT
= 9007199254740992LL;
448 Formattable::getInt64(UErrorCode
& status
) const
450 if (U_FAILURE(status
)) {
455 case Formattable::kLong
:
456 case Formattable::kInt64
:
457 return fValue
.fInt64
;
458 case Formattable::kDouble
:
459 if (fValue
.fDouble
> (double)U_INT64_MAX
) {
460 status
= U_INVALID_FORMAT_ERROR
;
462 } else if (fValue
.fDouble
< (double)U_INT64_MIN
) {
463 status
= U_INVALID_FORMAT_ERROR
;
465 } else if (fabs(fValue
.fDouble
) > U_DOUBLE_MAX_EXACT_INT
&& fDecimalQuantity
!= NULL
) {
466 if (fDecimalQuantity
->fitsInLong(true)) {
467 return fDecimalQuantity
->toLong();
470 status
= U_INVALID_FORMAT_ERROR
;
471 return fDecimalQuantity
->isNegative() ? U_INT64_MIN
: U_INT64_MAX
;
474 return (int64_t)fValue
.fDouble
;
476 case Formattable::kObject
:
477 if (fValue
.fObject
== NULL
) {
478 status
= U_MEMORY_ALLOCATION_ERROR
;
481 if (instanceOfMeasure(fValue
.fObject
)) {
482 return ((const Measure
*) fValue
.fObject
)->
483 getNumber().getInt64(status
);
487 status
= U_INVALID_FORMAT_ERROR
;
492 // -------------------------------------
494 Formattable::getDouble(UErrorCode
& status
) const
496 if (U_FAILURE(status
)) {
501 case Formattable::kLong
:
502 case Formattable::kInt64
: // loses precision
503 return (double)fValue
.fInt64
;
504 case Formattable::kDouble
:
505 return fValue
.fDouble
;
506 case Formattable::kObject
:
507 if (fValue
.fObject
== NULL
) {
508 status
= U_MEMORY_ALLOCATION_ERROR
;
511 // TODO Later replace this with instanceof call
512 if (instanceOfMeasure(fValue
.fObject
)) {
513 return ((const Measure
*) fValue
.fObject
)->
514 getNumber().getDouble(status
);
518 status
= U_INVALID_FORMAT_ERROR
;
524 Formattable::getObject() const {
525 return (fType
== kObject
) ? fValue
.fObject
: NULL
;
528 // -------------------------------------
529 // Sets the value to a double value d.
532 Formattable::setDouble(double d
)
539 // -------------------------------------
540 // Sets the value to a long value l.
543 Formattable::setLong(int32_t l
)
550 // -------------------------------------
551 // Sets the value to an int64 value ll.
554 Formattable::setInt64(int64_t ll
)
561 // -------------------------------------
562 // Sets the value to a Date instance d.
565 Formattable::setDate(UDate d
)
572 // -------------------------------------
573 // Sets the value to a string value stringToCopy.
576 Formattable::setString(const UnicodeString
& stringToCopy
)
580 fValue
.fString
= new UnicodeString(stringToCopy
);
583 // -------------------------------------
584 // Sets the value to an array of Formattable objects.
587 Formattable::setArray(const Formattable
* array
, int32_t count
)
591 fValue
.fArrayAndCount
.fArray
= createArrayCopy(array
, count
);
592 fValue
.fArrayAndCount
.fCount
= count
;
595 // -------------------------------------
596 // Adopts the stringToAdopt value.
599 Formattable::adoptString(UnicodeString
* stringToAdopt
)
603 fValue
.fString
= stringToAdopt
;
606 // -------------------------------------
607 // Adopts the array value and its count.
610 Formattable::adoptArray(Formattable
* array
, int32_t count
)
614 fValue
.fArrayAndCount
.fArray
= array
;
615 fValue
.fArrayAndCount
.fCount
= count
;
619 Formattable::adoptObject(UObject
* objectToAdopt
) {
622 fValue
.fObject
= objectToAdopt
;
625 // -------------------------------------
627 Formattable::getString(UnicodeString
& result
, UErrorCode
& status
) const
629 if (fType
!= kString
) {
630 setError(status
, U_INVALID_FORMAT_ERROR
);
633 if (fValue
.fString
== NULL
) {
634 setError(status
, U_MEMORY_ALLOCATION_ERROR
);
636 result
= *fValue
.fString
;
642 // -------------------------------------
644 Formattable::getString(UErrorCode
& status
) const
646 if (fType
!= kString
) {
647 setError(status
, U_INVALID_FORMAT_ERROR
);
650 if (fValue
.fString
== NULL
) {
651 setError(status
, U_MEMORY_ALLOCATION_ERROR
);
654 return *fValue
.fString
;
657 // -------------------------------------
659 Formattable::getString(UErrorCode
& status
)
661 if (fType
!= kString
) {
662 setError(status
, U_INVALID_FORMAT_ERROR
);
665 if (fValue
.fString
== NULL
) {
666 setError(status
, U_MEMORY_ALLOCATION_ERROR
);
669 return *fValue
.fString
;
672 // -------------------------------------
674 Formattable::getArray(int32_t& count
, UErrorCode
& status
) const
676 if (fType
!= kArray
) {
677 setError(status
, U_INVALID_FORMAT_ERROR
);
681 count
= fValue
.fArrayAndCount
.fCount
;
682 return fValue
.fArrayAndCount
.fArray
;
685 // -------------------------------------
686 // Gets the bogus string, ensures mondo bogosity.
689 Formattable::getBogus() const
691 return (UnicodeString
*)&fBogus
; /* cast away const :-( */
695 // --------------------------------------
696 StringPiece
Formattable::getDecimalNumber(UErrorCode
&status
) {
697 if (U_FAILURE(status
)) {
700 if (fDecimalStr
!= NULL
) {
701 return fDecimalStr
->toStringPiece();
704 CharString
*decimalStr
= internalGetCharString(status
);
705 if(decimalStr
== NULL
) {
706 return ""; // getDecimalNumber returns "" for error cases
708 return decimalStr
->toStringPiece();
712 CharString
*Formattable::internalGetCharString(UErrorCode
&status
) {
713 if(fDecimalStr
== NULL
) {
714 if (fDecimalQuantity
== NULL
) {
715 // No decimal number for the formattable yet. Which means the value was
716 // set directly by the user as an int, int64 or double. If the value came
717 // from parsing, or from the user setting a decimal number, fDecimalNum
718 // would already be set.
720 LocalPointer
<DecimalQuantity
> dq(new DecimalQuantity(), status
);
721 if (U_FAILURE(status
)) { return nullptr; }
722 populateDecimalQuantity(*dq
, status
);
723 if (U_FAILURE(status
)) { return nullptr; }
724 fDecimalQuantity
= dq
.orphan();
727 fDecimalStr
= new CharString();
728 if (fDecimalStr
== NULL
) {
729 status
= U_MEMORY_ALLOCATION_ERROR
;
732 // Older ICUs called uprv_decNumberToString here, which is not exactly the same as
733 // DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does
734 // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?).
735 if (fDecimalQuantity
->isInfinite()) {
736 fDecimalStr
->append("Infinity", status
);
737 } else if (fDecimalQuantity
->isNaN()) {
738 fDecimalStr
->append("NaN", status
);
739 } else if (fDecimalQuantity
->isZero()) {
740 fDecimalStr
->append("0", -1, status
);
741 } else if (fType
==kLong
|| fType
==kInt64
|| // use toPlainString for integer types
742 (fDecimalQuantity
->getMagnitude() != INT32_MIN
&& std::abs(fDecimalQuantity
->getMagnitude()) < 5)) {
743 fDecimalStr
->appendInvariantChars(fDecimalQuantity
->toPlainString(), status
);
745 fDecimalStr
->appendInvariantChars(fDecimalQuantity
->toScientificString(), status
);
752 Formattable::populateDecimalQuantity(number::impl::DecimalQuantity
& output
, UErrorCode
& status
) const {
753 if (fDecimalQuantity
!= nullptr) {
754 output
= *fDecimalQuantity
;
760 output
.setToDouble(this->getDouble());
761 output
.roundToInfinity();
764 output
.setToInt(this->getLong());
767 output
.setToLong(this->getInt64());
770 // The formattable's value is not a numeric type.
771 status
= U_INVALID_STATE_ERROR
;
775 // ---------------------------------------
777 Formattable::adoptDecimalQuantity(DecimalQuantity
*dq
) {
778 if (fDecimalQuantity
!= NULL
) {
779 delete fDecimalQuantity
;
781 fDecimalQuantity
= dq
;
782 if (dq
== NULL
) { // allow adoptDigitList(NULL) to clear
786 // Set the value into the Union of simple type values.
787 // Cannot use the set() functions because they would delete the fDecimalNum value.
788 if (fDecimalQuantity
->fitsInLong()) {
789 fValue
.fInt64
= fDecimalQuantity
->toLong();
790 if (fValue
.fInt64
<= INT32_MAX
&& fValue
.fInt64
>= INT32_MIN
) {
797 fValue
.fDouble
= fDecimalQuantity
->toDouble();
802 // ---------------------------------------
804 Formattable::setDecimalNumber(StringPiece numberString
, UErrorCode
&status
) {
805 if (U_FAILURE(status
)) {
810 auto* dq
= new DecimalQuantity();
811 dq
->setToDecNumber(numberString
, status
);
812 adoptDecimalQuantity(dq
);
814 // Note that we do not hang on to the caller's input string.
815 // If we are asked for the string, we will regenerate one from fDecimalQuantity.
819 //----------------------------------------------------
821 //----------------------------------------------------
827 #include "unicode/datefmt.h"
830 class FormattableStreamer
/* not : public UObject because all methods are static */ {
832 static void streamOut(ostream
& stream
, const Formattable
& obj
);
835 FormattableStreamer() {} // private - forbid instantiation
838 // This is for debugging purposes only. This will send a displayable
839 // form of the Formattable object to the output stream.
842 FormattableStreamer::streamOut(ostream
& stream
, const Formattable
& obj
)
844 static DateFormat
*defDateFormat
= 0;
846 UnicodeString buffer
;
847 switch(obj
.getType()) {
848 case Formattable::kDate
:
849 // Creates a DateFormat instance for formatting the
851 if (defDateFormat
== 0) {
852 defDateFormat
= DateFormat::createInstance();
854 defDateFormat
->format(obj
.getDate(), buffer
);
857 case Formattable::kDouble
:
858 // Output the double as is.
859 stream
<< obj
.getDouble() << 'D';
861 case Formattable::kLong
:
862 // Output the double as is.
863 stream
<< obj
.getLong() << 'L';
865 case Formattable::kString
:
866 // Output the double as is. Please see UnicodeString console
867 // I/O routine for more details.
868 stream
<< '"' << obj
.getString(buffer
) << '"';
870 case Formattable::kArray
:
872 const Formattable
* array
;
873 array
= obj
.getArray(count
);
875 // Recursively calling the console I/O routine for each element in the array.
876 for (i
=0; i
<count
; ++i
) {
877 FormattableStreamer::streamOut(stream
, array
[i
]);
878 stream
<< ( (i
==(count
-1)) ? "" : ", " );
883 // Not a recognizable Formattable object.
884 stream
<< "INVALID_Formattable";
894 /* ---- UFormattable implementation ---- */
898 U_DRAFT UFormattable
* U_EXPORT2
899 ufmt_open(UErrorCode
*status
) {
900 if( U_FAILURE(*status
) ) {
903 UFormattable
*fmt
= (new Formattable())->toUFormattable();
906 *status
= U_MEMORY_ALLOCATION_ERROR
;
911 U_DRAFT
void U_EXPORT2
912 ufmt_close(UFormattable
*fmt
) {
913 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
918 U_INTERNAL UFormattableType U_EXPORT2
919 ufmt_getType(const UFormattable
*fmt
, UErrorCode
*status
) {
920 if(U_FAILURE(*status
)) {
921 return (UFormattableType
)UFMT_COUNT
;
923 const Formattable
*obj
= Formattable::fromUFormattable(fmt
);
924 return (UFormattableType
)obj
->getType();
928 U_INTERNAL UBool U_EXPORT2
929 ufmt_isNumeric(const UFormattable
*fmt
) {
930 const Formattable
*obj
= Formattable::fromUFormattable(fmt
);
931 return obj
->isNumeric();
934 U_DRAFT UDate U_EXPORT2
935 ufmt_getDate(const UFormattable
*fmt
, UErrorCode
*status
) {
936 const Formattable
*obj
= Formattable::fromUFormattable(fmt
);
938 return obj
->getDate(*status
);
941 U_DRAFT
double U_EXPORT2
942 ufmt_getDouble(UFormattable
*fmt
, UErrorCode
*status
) {
943 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
945 return obj
->getDouble(*status
);
948 U_DRAFT
int32_t U_EXPORT2
949 ufmt_getLong(UFormattable
*fmt
, UErrorCode
*status
) {
950 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
952 return obj
->getLong(*status
);
956 U_DRAFT
const void *U_EXPORT2
957 ufmt_getObject(const UFormattable
*fmt
, UErrorCode
*status
) {
958 const Formattable
*obj
= Formattable::fromUFormattable(fmt
);
960 const void *ret
= obj
->getObject();
962 (obj
->getType() != Formattable::kObject
) &&
963 U_SUCCESS( *status
)) {
964 *status
= U_INVALID_FORMAT_ERROR
;
969 U_DRAFT
const UChar
* U_EXPORT2
970 ufmt_getUChars(UFormattable
*fmt
, int32_t *len
, UErrorCode
*status
) {
971 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
973 // avoid bogosity by checking the type first.
974 if( obj
->getType() != Formattable::kString
) {
975 if( U_SUCCESS(*status
) ){
976 *status
= U_INVALID_FORMAT_ERROR
;
981 // This should return a valid string
982 UnicodeString
&str
= obj
->getString(*status
);
983 if( U_SUCCESS(*status
) && len
!= NULL
) {
986 return str
.getTerminatedBuffer();
989 U_DRAFT
int32_t U_EXPORT2
990 ufmt_getArrayLength(const UFormattable
* fmt
, UErrorCode
*status
) {
991 const Formattable
*obj
= Formattable::fromUFormattable(fmt
);
994 (void)obj
->getArray(count
, *status
);
998 U_DRAFT UFormattable
* U_EXPORT2
999 ufmt_getArrayItemByIndex(UFormattable
* fmt
, int32_t n
, UErrorCode
*status
) {
1000 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
1002 (void)obj
->getArray(count
, *status
);
1003 if(U_FAILURE(*status
)) {
1005 } else if(n
<0 || n
>=count
) {
1006 setError(*status
, U_INDEX_OUTOFBOUNDS_ERROR
);
1009 return (*obj
)[n
].toUFormattable(); // returns non-const Formattable
1013 U_DRAFT
const char * U_EXPORT2
1014 ufmt_getDecNumChars(UFormattable
*fmt
, int32_t *len
, UErrorCode
*status
) {
1015 if(U_FAILURE(*status
)) {
1018 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
1019 CharString
*charString
= obj
->internalGetCharString(*status
);
1020 if(U_FAILURE(*status
)) {
1023 if(charString
== NULL
) {
1024 *status
= U_MEMORY_ALLOCATION_ERROR
;
1028 *len
= charString
->length();
1030 return charString
->data();
1034 U_DRAFT
int64_t U_EXPORT2
1035 ufmt_getInt64(UFormattable
*fmt
, UErrorCode
*status
) {
1036 Formattable
*obj
= Formattable::fromUFormattable(fmt
);
1037 return obj
->getInt64(*status
);
1040 #endif /* #if !UCONFIG_NO_FORMATTING */