From: Steven R. Loomis Date: Wed, 26 Jun 2013 06:31:09 +0000 (+0000) Subject: ICU-7912 C wrapper for Formattable - UFormattable X-Git-Tag: milestone-59-0-1~2815 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ae061ff78f96798c2db1221222828e5950b2ea36;p=icu ICU-7912 C wrapper for Formattable - UFormattable X-SVN-Rev: 33849 --- diff --git a/icu4c/source/i18n/fmtable.cpp b/icu4c/source/i18n/fmtable.cpp index 274b3d782d0..4e2eedbcf04 100644 --- a/icu4c/source/i18n/fmtable.cpp +++ b/icu4c/source/i18n/fmtable.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2012, International Business Machines Corporation and * +* Copyright (C) 1997-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -22,6 +22,7 @@ #include "unicode/ustring.h" #include "unicode/measure.h" #include "unicode/curramt.h" +#include "unicode/uformattable.h" #include "charstr.h" #include "cmemory.h" #include "cstring.h" @@ -695,46 +696,56 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) { return ""; } if (fDecimalStr != NULL) { - return fDecimalStr->toStringPiece(); + return fDecimalStr->toStringPiece(); } - if (fDecimalNum == NULL) { + CharString *decimalStr = internalGetCharString(status); + if(decimalStr == NULL) { + return ""; // getDecimalNumber returns "" for error cases + } else { + return decimalStr->toStringPiece(); + } +} + +CharString *Formattable::internalGetCharString(UErrorCode &status) { + if(fDecimalStr == NULL) { + if (fDecimalNum == NULL) { // No decimal number for the formattable yet. Which means the value was // set directly by the user as an int, int64 or double. If the value came // from parsing, or from the user setting a decimal number, fDecimalNum // would already be set. // - fDecimalNum = new DigitList; // TODO: use internal digit list + fDecimalNum = new DigitList; // TODO: use internal digit list if (fDecimalNum == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return ""; + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; } switch (fType) { case kDouble: - fDecimalNum->set(this->getDouble()); - break; + fDecimalNum->set(this->getDouble()); + break; case kLong: - fDecimalNum->set(this->getLong()); - break; + fDecimalNum->set(this->getLong()); + break; case kInt64: - fDecimalNum->set(this->getInt64()); - break; + fDecimalNum->set(this->getInt64()); + break; default: - // The formattable's value is not a numeric type. - status = U_INVALID_STATE_ERROR; - return ""; + // The formattable's value is not a numeric type. + status = U_INVALID_STATE_ERROR; + return NULL; } - } + } - fDecimalStr = new CharString; - if (fDecimalStr == NULL) { + fDecimalStr = new CharString; + if (fDecimalStr == NULL) { status = U_MEMORY_ALLOCATION_ERROR; - return ""; + return NULL; + } + fDecimalNum->getDecimal(*fDecimalStr, status); } - fDecimalNum->getDecimal(*fDecimalStr, status); - - return fDecimalStr->toStringPiece(); + return fDecimalStr; } @@ -882,6 +893,197 @@ FormattableStreamer::streamOut(ostream& stream, const Formattable& obj) #endif +/* ---- UFormattable stuff ---- */ + + +U_DRAFT UFormattable* U_EXPORT2 +ufmt_open(UErrorCode *status) { + if( U_FAILURE(*status) ) { + return NULL; + } + UFormattable *fmt = (new Formattable())->toUFormattable(); + + if( fmt == NULL ) { + *status = U_MEMORY_ALLOCATION_ERROR; + } + return fmt; +} + +U_DRAFT void U_EXPORT2 +ufmt_close(UFormattable *fmt) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + delete obj; +} + +U_INTERNAL UFormattableType U_EXPORT2 +ufmt_getType(UFormattable *fmt, UErrorCode *status) { + if(U_FAILURE(*status)) { + return (UFormattableType)-1; + } + Formattable *obj = Formattable::fromUFormattable(fmt); + switch( obj->getType() ) { + case Formattable::kDate: + return UFMT_DATE; + break; + case Formattable::kDouble: + return UFMT_DOUBLE; + break; + case Formattable::kLong: + return UFMT_LONG; + break; + case Formattable::kString: + return UFMT_STRING; + break; + case Formattable::kArray: + return UFMT_ARRAY; + break; + case Formattable::kInt64: + return UFMT_INT64; + break; + case Formattable::kObject: + return UFMT_OBJECT; + break; + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + return (UFormattableType)-1; // invalid + } +} + + +U_INTERNAL UBool U_EXPORT2 +ufmt_isNumeric(UFormattable *fmt) { + Formattable *obj = Formattable::fromUFormattable(fmt); + return obj->isNumeric(); +} + +U_DRAFT UDate U_EXPORT2 +ufmt_getDate(UFormattable *fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + return obj->getDate(*status); +} + +U_DRAFT double U_EXPORT2 +ufmt_getDouble(UFormattable *fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + return obj->getDouble(*status); +} + +U_DRAFT int32_t U_EXPORT2 +ufmt_getLong(UFormattable *fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + return obj->getLong(*status); +} + + +U_DRAFT const void *U_EXPORT2 +ufmt_getObject(UFormattable *fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + const void *ret = obj->getObject(); + if( ret==NULL && + (obj->getType() != Formattable::kObject) && + U_SUCCESS( *status )) { + *status = U_INVALID_FORMAT_ERROR; + } + return ret; +} + +U_DRAFT const UChar* U_EXPORT2 +ufmt_getUChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + // avoid bogosity by checking the type first. + if( obj->getType() != Formattable::kString ) { + if( U_SUCCESS(*status) ){ + *status = U_INVALID_FORMAT_ERROR; + } + return NULL; + } + + // This should return a valid string + UnicodeString &str = obj->getString(*status); + if( U_SUCCESS(*status) && len != NULL ) { + *len = str.length(); + } + return str.getTerminatedBuffer(); +} + +U_DRAFT int32_t U_EXPORT2 +ufmt_getArrayLength(UFormattable* fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + + int32_t count; + (void)obj->getArray(count, *status); + return count; +} + +U_DRAFT UFormattable * U_EXPORT2 +ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + int32_t count; + (void)obj->getArray(count, *status); + if(U_FAILURE(*status)) { + return NULL; + } else if(n<0 || n>=count) { + setError(*status, U_INDEX_OUTOFBOUNDS_ERROR); + return NULL; + } else { + return (*obj)[n].toUFormattable(); // returns non-const Formattable + } +} + +U_DRAFT const char * U_EXPORT2 +ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { + if(U_FAILURE(*status)) { + return ""; + } + Formattable *obj = Formattable::fromUFormattable(fmt); + CharString *charString = obj->internalGetCharString(*status); + if(U_FAILURE(*status)) { + return ""; + } + if(charString == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return ""; + } else { + if(len!=NULL) { + *len = charString->length(); + } + return charString->data(); + } +} + +// make-a-copy version +// U_DRAFT int32_t U_EXPORT2 +// ufmt_getDecNumChars(UFormattable *fmt, char *buf, int32_t len, UErrorCode *status) { +// if(U_FAILURE(*status)) { +// return 0; +// } +// Formattable *obj = Formattable::fromUFormattable(fmt); +// CharString *charString = obj->internalGetCharString(*status); +// if(U_FAILURE(*status)) { +// return 0; +// } +// if(charString == NULL) { +// *status = U_MEMORY_ALLOCATION_ERROR; +// return 0; +// } else { +// return charString->extract(buf, len, *status); +// } +// } + + +U_DRAFT int64_t U_EXPORT2 +ufmt_getInt64(UFormattable *fmt, UErrorCode *status) { + Formattable *obj = Formattable::fromUFormattable(fmt); + return obj->getInt64(*status); +} + + U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj index 0b3598e8f21..fc33d41529b 100644 --- a/icu4c/source/i18n/i18n.vcxproj +++ b/icu4c/source/i18n/i18n.vcxproj @@ -1,4 +1,4 @@ - + @@ -879,6 +879,20 @@ ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + + + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) diff --git a/icu4c/source/i18n/unicode/fmtable.h b/icu4c/source/i18n/unicode/fmtable.h index 7959d38b161..d4cfccc76f2 100644 --- a/icu4c/source/i18n/unicode/fmtable.h +++ b/icu4c/source/i18n/unicode/fmtable.h @@ -16,16 +16,18 @@ #define FMTABLE_H #include "unicode/utypes.h" -#include "unicode/unistr.h" -#include "unicode/stringpiece.h" /** - * \file - * \brief C++ API: Formattable is a thin wrapper for primitive numeric types. + * \file + * \brief C++ API: Formattable is a thin wrapper for primitive types used for formatting and parsing */ #if !UCONFIG_NO_FORMATTING +#include "unicode/unistr.h" +#include "unicode/stringpiece.h" +#include "unicode/uformattable.h" + U_NAMESPACE_BEGIN class CharString; @@ -84,7 +86,7 @@ public: * Creates a Formattable object with a UDate instance. * @param d the UDate instance. * @param flag the flag to indicate this is a date. Always set it to kIsDate - * @stable ICU 2.0 + * @stable ICU 2.0 */ Formattable(UDate d, ISDATE flag); @@ -183,8 +185,8 @@ public: * @stable ICU 2.0 */ UBool operator==(const Formattable &other) const; - - /** + + /** * Equality operator. * @param other the object to be compared with. * @return TRUE if other are unequal to this, FALSE otherwise. @@ -193,7 +195,7 @@ public: UBool operator!=(const Formattable& other) const { return !operator==(other); } - /** + /** * Destructor. * @stable ICU 2.0 */ @@ -212,7 +214,7 @@ public: */ Formattable *clone() const; - /** + /** * Selector for flavor of data type contained within a * Formattable object. Formattable is a union of several * different types, and at any time contains exactly one type. @@ -275,7 +277,7 @@ public: * @stable ICU 2.0 */ Type getType(void) const; - + /** * Returns TRUE if the data type of this Formattable object * is kDouble, kLong, kInt64 or kDecimalNumber. @@ -283,13 +285,13 @@ public: * @stable ICU 3.0 */ UBool isNumeric() const; - + /** * Gets the double value of this object. If this object is not of type * kDouble then the result is undefined. * @return the double value of this object. * @stable ICU 2.0 - */ + */ double getDouble(void) const { return fValue.fDouble; } /** @@ -303,7 +305,7 @@ public: * @param status the error code * @return the double value of this object. * @stable ICU 3.0 - */ + */ double getDouble(UErrorCode& status) const; /** @@ -311,7 +313,7 @@ public: * kLong then the result is undefined. * @return the long value of this object. * @stable ICU 2.0 - */ + */ int32_t getLong(void) const { return (int32_t)fValue.fInt64; } /** @@ -329,7 +331,7 @@ public: * @param status the error code * @return the long value of this object. * @stable ICU 3.0 - */ + */ int32_t getLong(UErrorCode& status) const; /** @@ -337,7 +339,7 @@ public: * kInt64 then the result is undefined. * @return the int64 value of this object. * @stable ICU 2.8 - */ + */ int64_t getInt64(void) const { return fValue.fInt64; } /** @@ -354,7 +356,7 @@ public: * @param status the error code * @return the int64 value of this object. * @stable ICU 3.0 - */ + */ int64_t getInt64(UErrorCode& status) const; /** @@ -362,7 +364,7 @@ public: * kDate then the result is undefined. * @return the Date value of this object. * @stable ICU 2.0 - */ + */ UDate getDate() const { return fValue.fDate; } /** @@ -372,7 +374,7 @@ public: * @param status the error code. * @return the Date value of this object. * @stable ICU 3.0 - */ + */ UDate getDate(UErrorCode& status) const; /** @@ -381,7 +383,7 @@ public: * @param result Output param to receive the Date value of this object. * @return A reference to 'result'. * @stable ICU 2.0 - */ + */ UnicodeString& getString(UnicodeString& result) const { result=*fValue.fString; return result; } @@ -390,10 +392,10 @@ public: * string, status is set to U_INVALID_FORMAT_ERROR and a bogus * string is returned. * @param result Output param to receive the Date value of this object. - * @param status the error code. + * @param status the error code. * @return A reference to 'result'. * @stable ICU 3.0 - */ + */ UnicodeString& getString(UnicodeString& result, UErrorCode& status) const; /** @@ -427,7 +429,7 @@ public: * Gets a reference to the string value of this object. If the * type is not a string, status is set to U_INVALID_FORMAT_ERROR * and the result is a bogus string. - * @param status the error code. + * @param status the error code. * @return a reference to the string value of this object. * @stable ICU 3.0 */ @@ -439,7 +441,7 @@ public: * @param count fill-in with the count of this object. * @return the array value of this object. * @stable ICU 2.0 - */ + */ const Formattable* getArray(int32_t& count) const { count=fValue.fArrayAndCount.fCount; return fValue.fArrayAndCount.fArray; } @@ -448,10 +450,10 @@ public: * not an array, status is set to U_INVALID_FORMAT_ERROR, count is * set to 0, and the result is NULL. * @param count fill-in with the count of this object. - * @param status the error code. + * @param status the error code. * @return the array value of this object. * @stable ICU 3.0 - */ + */ const Formattable* getArray(int32_t& count, UErrorCode& status) const; /** @@ -463,7 +465,7 @@ public: * @stable ICU 2.0 */ Formattable& operator[](int32_t index) { return fValue.fArrayAndCount.fArray[index]; } - + /** * Returns a pointer to the UObject contained within this * formattable, or NULL if this object does not contain a UObject. @@ -478,7 +480,7 @@ public: * For values obtained by parsing, the returned decimal number retains * the full precision and range of the original input, unconstrained by * the limits of a double floating point or a 64 bit int. - * + * * This function is not thread safe, and therfore is not declared const, * even though it is logically const. * @@ -497,7 +499,7 @@ public: * kDouble. * @param d the new double value to be set. * @stable ICU 2.0 - */ + */ void setDouble(double d); /** @@ -505,7 +507,7 @@ public: * kLong. * @param l the new long value to be set. * @stable ICU 2.0 - */ + */ void setLong(int32_t l); /** @@ -513,7 +515,7 @@ public: * kInt64. * @param ll the new int64 value to be set. * @stable ICU 2.8 - */ + */ void setInt64(int64_t ll); /** @@ -521,7 +523,7 @@ public: * kDate. * @param d the new Date value to be set. * @stable ICU 2.0 - */ + */ void setDate(UDate d); /** @@ -529,7 +531,7 @@ public: * kString. * @param stringToCopy the new string value to be set. * @stable ICU 2.0 - */ + */ void setString(const UnicodeString& stringToCopy); /** @@ -538,7 +540,7 @@ public: * @param array the array value. * @param count the number of array elements to be copied. * @stable ICU 2.0 - */ + */ void setArray(const Formattable* array, int32_t count); /** @@ -546,16 +548,16 @@ public: * changes the type to kArray. * @param stringToAdopt the new string value to be adopted. * @stable ICU 2.0 - */ + */ void adoptString(UnicodeString* stringToAdopt); /** * Sets and adopts the array value and count of this object and * changes the type to kArray. * @stable ICU 2.0 - */ + */ void adoptArray(Formattable* array, int32_t count); - + /** * Sets and adopts the UObject value of this object and changes * the type to kObject. After this call, the caller must not @@ -567,7 +569,7 @@ public: /** * Sets the the numeric value from a decimal number string, and changes - * the type to to a numeric type appropriate for the number. + * the type to to a numeric type appropriate for the number. * The syntax of the number is a "numeric string" * as defined in the Decimal Arithmetic Specification, available at * http://speleotrove.com/decimal @@ -596,13 +598,29 @@ public: */ static UClassID U_EXPORT2 getStaticClassID(); + /** + * Convert the UFormattable to a Formattable. Internally, this is a reinterpret_cast. + * @param fmt a valid UFormattable + * @return the UFormattable as a Formattable object pointer. This is an alias to the original + * UFormattable, and so is only valid while the original argument remains in scope. + * @draft ICU 52 + */ + static inline Formattable *fromUFormattable(UFormattable *fmt); + + /** + * Convert this object pointer to a UFormattable. + * @return this object as a UFormattable pointer. This is an alias to the original UFormattable, + * and so is only valid while the original argument remains in scope. + */ + inline UFormattable *toUFormattable(); + #ifndef U_HIDE_DEPRECATED_API /** * Deprecated variant of getLong(UErrorCode&). * @param status the error code * @return the long value of this object. * @deprecated ICU 3.0 use getLong(UErrorCode&) instead - */ + */ inline int32_t getLong(UErrorCode* status) const; #endif /* U_HIDE_DEPRECATED_API */ @@ -629,6 +647,14 @@ public: * @internal */ void adoptDigitList(DigitList *dl); + + /** + * Internal function to return the CharString pointer. + * @param status error code + * @return pointer to the CharString - may become invalid if the object is modified + */ + CharString *internalGetCharString(UErrorCode &status); + #endif /* U_HIDE_INTERNAL_API */ private: @@ -689,6 +715,14 @@ inline int32_t Formattable::getLong(UErrorCode* status) const { return getLong(*status); } +inline UFormattable* Formattable::toUFormattable() { + return (UFormattable*)(this); +} + +inline Formattable* Formattable::fromUFormattable(UFormattable *fmt) { + return reinterpret_cast(fmt); +} + U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/uformattable.h b/icu4c/source/i18n/unicode/uformattable.h new file mode 100644 index 00000000000..9107ec4465e --- /dev/null +++ b/icu4c/source/i18n/unicode/uformattable.h @@ -0,0 +1,224 @@ +/* +TODO +* copy C++ apidoc concerning error codes to appropriate wrapper functions +*/ + + +/* +******************************************************************************** +* Copyright (C) 2013, International Business Machines Corporation and others. +* All Rights Reserved. +******************************************************************************** +* +* File UFORMATTABLE.H +* +* Modification History: +* +* Date Name Description +* 2013 Jul 7 srl New +******************************************************************************** +*/ + +/** + * \file + * \brief C API: UFormattable is a thin wrapper for primitive types used for formatting and parsing. + * + * This is a C interface to the icu::Formattable class. Static functions on this class convert + * to and from this interface (via reinterpret_cast). Note that Formattables (and thus UFormattables) + * are mutable, and many operations (even getters) may actually modify the internal state. For this + * reason, UFormattables are not thread safe, and should not be shared between threads. + */ + +#ifndef FORMATTABLE_H +#define FORMATTABLE_H + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/localpointer.h" + +/** + * Enum designating the type of a UFormattable instance. + * Practically, this indicates which of the getters would return without conversion + * or error. + * @see icu::Formattable::Type + * @draft ICU 52 + */ +typedef enum UFormattableType { + UFMT_DATE = 0, /**< ufmt_getDate() will return without conversion. */ + UFMT_DOUBLE, /**< ufmt_getDouble() will return without conversion. */ + UFMT_LONG, /**< ufmt_getLong() will return without conversion. */ + UFMT_INT64, /**< ufmt_getInt64() will return without conversion. */ + UFMT_OBJECT, /**< ufmt_getObject() will return without conversion. */ + UFMT_STRING, /**< ufmt_getUChars() will return without conversion. */ + UFMT_ARRAY, /**< ufmt_countArray() and ufmt_getArray() will return the value. */ + UFMT_COUNT /**< Count of defined UFormattableType values */ +} UFormattableType; + + +/** + * Opaque type representing various types of data which may be used for formatting + * and parsing operations. + * @see icu::Formattable + * @draft ICU 52 + */ +typedef void *UFormattable; + +/** + * Initialize a UFormattable, to type UNUM_LONG, value 0 + * may return error if memory allocation failed. + * parameter status error code. + * @draft ICU 52 + * @return the new UFormattable + */ +U_DRAFT UFormattable* U_EXPORT2 +ufmt_open(UErrorCode* status); + +/** + * Cleanup any additional memory allocated by this UFormattable. + * @draft ICU 52 + */ +U_DRAFT void U_EXPORT2 +ufmt_close(UFormattable* fmt); + +#if U_SHOW_CPLUSPLUS_API + +U_NAMESPACE_BEGIN + +/** + * \class LocalUFormattablePointer + * "Smart pointer" class, closes a UFormattable via ufmt_close(). + * For most methods see the LocalPointerBase base class. + * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 52 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattablePointer, UFormattable, ufmt_close); + +U_NAMESPACE_END + +#endif + +/** + * Return the type of this object + * @param fmt the UFormattable object + * @status status code - U_ILLEGAL_ARGUMENT_ERROR is returned if the UFormattable contains data not supported by + * the API + * @return the value as a UFormattableType + * @internal + */ +U_INTERNAL UFormattableType U_EXPORT2 +ufmt_getType(UFormattable* fmt, UErrorCode *status); + +/** + * Return the type of this object + * @param fmt the UFormattable object + * @return true if the object is a double, long, or int64 value. + * @internal + */ +U_INTERNAL UBool U_EXPORT2 +ufmt_isNumeric(UFormattable* fmt); + + +/** + * Get the value as a date, converting if need be. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @return the value + * @draft ICU 52 + */ +U_DRAFT UDate U_EXPORT2 +ufmt_getDate(UFormattable* fmt, UErrorCode *status); + +/** + * Get the value as a double, converting if need be. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @return the value + * @draft ICU 52 + */ +U_DRAFT double U_EXPORT2 +ufmt_getDouble(UFormattable* fmt, UErrorCode *status); + +/** + * Get the value as a int32_t, converting if need be. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @return the value + * @draft ICU 52 + */ +U_DRAFT int32_t U_EXPORT2 +ufmt_getLong(UFormattable* fmt, UErrorCode *status); + + +/** + * Get the value as a int64_t, converting if need be. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @return the value + * @draft ICU 52 + */ +U_DRAFT int64_t U_EXPORT2 +ufmt_getInt64(UFormattable* fmt, UErrorCode *status); + +/** + * Get the value as an object. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @return the value as a const void*. It is a polymorphic C++ object. + * @draft ICU 52 + */ +U_DRAFT const void *U_EXPORT2 +ufmt_getObject(UFormattable* fmt, UErrorCode *status); + +/** + * Get the value as UChar string, converting if need be. + * This function is not thread safe and may modify the UFormattable if need be to terminate the buffer. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors + * @param len if non null, contains the string length on return + * @return the null terminated string value - must not be referenced after any other functions are called on this UFormattable. + * @draft ICU 52 + */ +U_DRAFT const UChar* U_EXPORT2 +ufmt_getUChars(UFormattable* fmt, int32_t *len, UErrorCode *status); + +/** + * Get the number of array objects contained. Invalid if the object is not an array type. + * @param fmt the UFormattable object + * @param status the error code - any conversion or format errors. U_ILLEGAL_ARGUMENT_ERROR if not an array type. + * @return the number of array objects + * @draft ICU 52 + */ +U_DRAFT int32_t U_EXPORT2 +ufmt_getArrayLength(UFormattable* fmt, UErrorCode *status); + +/** + * Get the specified value from the array of UFormattables. Invalid if the object is not an array type. + * @param fmt the UFormattable object + * #param n the number of the array to return (0 based). + * @param status the error code - any conversion or format errors. Returns an error if n is out of bounds. + * @return the nth array value, only valid while the containing UFormattable is valid + * @draft ICU 52 + */ +U_DRAFT UFormattable * U_EXPORT2 +ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status); + +/** + * Get the value as a C String, if it is a numeric type (isNumeric is true), or if is an Object + * with a numeric value. The returned string is not valid if any other function calls are made on this + * object, or if it is destroyed. + * @param fmt the UFormattable object + * @param len if non-null, on exit contains the string length (not including the terminating null) + * @param status the error code + * @return the character buffer, which is owned by the object and must not be accessed if any other functions are called on this object. + * @draft ICU 52 + */ +U_DRAFT const char * U_EXPORT2 +ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status); + +#endif + +#endif diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp index 345d058286a..b53f7d646fe 100644 --- a/icu4c/source/test/intltest/intltest.cpp +++ b/icu4c/source/test/intltest/intltest.cpp @@ -120,6 +120,12 @@ operator+(const UnicodeString& left, return left + buffer; } +UnicodeString +operator+(const UnicodeString& left, + int64_t num) { + return left + Int64ToUnicodeString(num); +} + #if !UCONFIG_NO_FORMATTING /** @@ -204,6 +210,12 @@ UnicodeString toString(int32_t n) { return UnicodeString() + (long)n; } + + +UnicodeString toString(UBool b) { + return b ? UnicodeString("TRUE"):UnicodeString("false"); +} + // stephen - cleaned up 05/05/99 UnicodeString operator+(const UnicodeString& left, char num) { return left + (long)num; } @@ -1768,6 +1780,40 @@ UBool IntlTest::assertEquals(const char* message, return TRUE; } +UBool IntlTest::assertEquals(const char* message, + int64_t expected, + int64_t actual) { + if (expected != actual) { + errln((UnicodeString)"FAIL: " + message + "; got " + + actual + + "; expected " + expected ); + return FALSE; + } +#ifdef VERBOSE_ASSERTIONS + else { + logln((UnicodeString)"Ok: " + message + "; got " + actual); + } +#endif + return TRUE; +} + +UBool IntlTest::assertEquals(const char* message, + UBool expected, + UBool actual) { + if (expected != actual) { + errln((UnicodeString)"FAIL: " + message + "; got " + + toString(actual) + + "; expected " + toString(expected)); + return FALSE; + } +#ifdef VERBOSE_ASSERTIONS + else { + logln((UnicodeString)"Ok: " + message + "; got " + toString(actual)); + } +#endif + return TRUE; +} + #if !UCONFIG_NO_FORMATTING UBool IntlTest::assertEquals(const char* message, const Formattable& expected, @@ -1820,6 +1866,21 @@ UBool IntlTest::assertEquals(const UnicodeString& message, const char* actual) { return assertEquals(extractToAssertBuf(message), expected, actual); } +UBool IntlTest::assertEquals(const UnicodeString& message, + UBool expected, + UBool actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} +UBool IntlTest::assertEquals(const UnicodeString& message, + int32_t expected, + int32_t actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} +UBool IntlTest::assertEquals(const UnicodeString& message, + int64_t expected, + int64_t actual) { + return assertEquals(extractToAssertBuf(message), expected, actual); +} //-------------------------------------------------------------------- // Time bomb - allows temporary behavior that expires at a given // release diff --git a/icu4c/source/test/intltest/intltest.h b/icu4c/source/test/intltest/intltest.h index e71576d259b..2b5e01d490b 100644 --- a/icu4c/source/test/intltest/intltest.h +++ b/icu4c/source/test/intltest/intltest.h @@ -51,21 +51,23 @@ U_NAMESPACE_USE //string-concatenation operator (moved from findword test by rtg) UnicodeString UCharToUnicodeString(UChar c); UnicodeString Int64ToUnicodeString(int64_t num); -//UnicodeString operator+(const UnicodeString& left, int64_t num); // Some compilers don't allow this because of the long type. +UnicodeString operator+(const UnicodeString& left, int64_t num); UnicodeString operator+(const UnicodeString& left, long num); UnicodeString operator+(const UnicodeString& left, unsigned long num); UnicodeString operator+(const UnicodeString& left, double num); -UnicodeString operator+(const UnicodeString& left, char num); -UnicodeString operator+(const UnicodeString& left, short num); -UnicodeString operator+(const UnicodeString& left, int num); -UnicodeString operator+(const UnicodeString& left, unsigned char num); -UnicodeString operator+(const UnicodeString& left, unsigned short num); -UnicodeString operator+(const UnicodeString& left, unsigned int num); +UnicodeString operator+(const UnicodeString& left, char num); +UnicodeString operator+(const UnicodeString& left, short num); +UnicodeString operator+(const UnicodeString& left, int num); +UnicodeString operator+(const UnicodeString& left, unsigned char num); +UnicodeString operator+(const UnicodeString& left, unsigned short num); +UnicodeString operator+(const UnicodeString& left, unsigned int num); UnicodeString operator+(const UnicodeString& left, float num); #if !UCONFIG_NO_FORMATTING UnicodeString toString(const Formattable& f); // liu UnicodeString toString(int32_t n); #endif +UnicodeString toString(UBool b); + //----------------------------------------------------------------------------- // Use the TESTCASE macro in subclasses of IntlTest. Define the @@ -178,6 +180,13 @@ public: void errln(const char *fmt, ...); void dataerr(const char *fmt, ...); void dataerrln(const char *fmt, ...); + + /** + * logs an error (even if status==U_ZERO_ERROR), but + * calls dataerrln() or errln() depending on the type of error. + * Does not report the status code. + * @param status parameter for selecting whether errln or dataerrln is called. + */ void errcheckln(UErrorCode status, const char *fmt, ...); // Print ALL named errors encountered so far @@ -236,12 +245,19 @@ protected: /* JUnit-like assertions. Each returns TRUE if it succeeds. */ UBool assertTrue(const char* message, UBool condition, UBool quiet=FALSE, UBool possibleDataError=FALSE, const char *file=NULL, int line=0); UBool assertFalse(const char* message, UBool condition, UBool quiet=FALSE); + /** + * @param possibleDataError - if TRUE, use dataerrln instead of errcheckln on failure + * @return TRUE on success, FALSE on failure. + */ UBool assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError=FALSE); UBool assertEquals(const char* message, const UnicodeString& expected, const UnicodeString& actual, UBool possibleDataError=FALSE); UBool assertEquals(const char* message, const char* expected, const char* actual); + UBool assertEquals(const char* message, UBool expected, + UBool actual); UBool assertEquals(const char* message, int32_t expected, int32_t actual); + UBool assertEquals(const char* message, int64_t expected, int64_t actual); #if !UCONFIG_NO_FORMATTING UBool assertEquals(const char* message, const Formattable& expected, const Formattable& actual); @@ -255,6 +271,9 @@ protected: const UnicodeString& actual); UBool assertEquals(const UnicodeString& message, const char* expected, const char* actual); + UBool assertEquals(const UnicodeString& message, UBool expected, UBool actual); + UBool assertEquals(const UnicodeString& message, int32_t expected, int32_t actual); + UBool assertEquals(const UnicodeString& message, int64_t expected, int64_t actual); virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); // overide ! diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index b909303c605..37c7d5da18d 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -121,6 +121,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n TESTCASE_AUTO(Test9087); TESTCASE_AUTO(TestFormatFastpaths); TESTCASE_AUTO(TestFormattableSize); + TESTCASE_AUTO(TestUFormattable); TESTCASE_AUTO(TestSignificantDigits); TESTCASE_AUTO(TestShowZero); TESTCASE_AUTO(TestCompatibleCurrencies); @@ -6789,6 +6790,226 @@ void NumberFormatTest::TestFormattableSize(void) { } } +UBool NumberFormatTest::testFormattableAsUFormattable(const char *file, int line, Formattable &f) { + UnicodeString fileLine = UnicodeString(file)+UnicodeString(":")+line+UnicodeString(": "); + + UFormattable *u = f.toUFormattable(); + logln(); + if (u == NULL) { + errln("%s:%d: Error: f.toUFormattable() retuned NULL."); + return FALSE; + } + logln("%s:%d: comparing Formattable with UFormattable", file, line); + logln(fileLine + toString(f)); + + UErrorCode status = U_ZERO_ERROR; + UErrorCode valueStatus = U_ZERO_ERROR; + UFormattableType expectUType = UFMT_COUNT; // invalid + + UBool triedExact = FALSE; // did we attempt an exact comparison? + UBool exactMatch = FALSE; // was the exact comparison true? + + switch( f.getType() ) { + case Formattable::kDate: + expectUType = UFMT_DATE; + exactMatch = (f.getDate()==ufmt_getDate(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kDouble: + expectUType = UFMT_DOUBLE; + exactMatch = (f.getDouble()==ufmt_getDouble(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kLong: + expectUType = UFMT_LONG; + exactMatch = (f.getLong()==ufmt_getLong(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kString: + expectUType = UFMT_STRING; + { + UnicodeString str; + f.getString(str); + int32_t len; + const UChar* uch = ufmt_getUChars(u, &len, &valueStatus); + if(U_SUCCESS(valueStatus)) { + UnicodeString str2(uch, len); + exactMatch = (str == str2); + } + triedExact = TRUE; + } + break; + case Formattable::kArray: + expectUType = UFMT_ARRAY; + triedExact = TRUE; + { + int32_t count = ufmt_getArrayLength(u, &valueStatus); + int32_t count2; + const Formattable *array2 = f.getArray(count2); + exactMatch = assertEquals(fileLine + " array count", count, count2); + + if(exactMatch) { + for(int i=0;U_SUCCESS(valueStatus) && i