ICU-7912 C wrapper for Formattable - UFormattable

X-SVN-Rev: 33849
This commit is contained in:
Steven R. Loomis 2013-06-26 06:31:09 +00:00
parent 20016a58db
commit ae061ff78f
8 changed files with 848 additions and 69 deletions

View File

@ -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 */

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@ -879,6 +879,20 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\uformattable.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>

View File

@ -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<Formattable *>(fmt);
}
U_NAMESPACE_END

View File

@ -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

View File

@ -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

View File

@ -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 !

View File

@ -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<count;i++) {
UFormattable *uu = ufmt_getArrayItemByIndex(u, i, &valueStatus);
if(*Formattable::fromUFormattable(uu) != (array2[i])) {
errln("%s:%d: operator== did not match at index[%d] - %p vs %p", file, line, i,
(const void*)Formattable::fromUFormattable(uu), (const void*)&(array2[i]));
exactMatch = FALSE;
} else {
if(!testFormattableAsUFormattable("(sub item)",i,*Formattable::fromUFormattable(uu))) {
exactMatch = FALSE;
}
}
}
}
}
break;
case Formattable::kInt64:
expectUType = UFMT_INT64;
exactMatch = (f.getInt64()==ufmt_getInt64(u, &valueStatus));
triedExact = TRUE;
break;
case Formattable::kObject:
expectUType = UFMT_OBJECT;
exactMatch = (f.getObject()==ufmt_getObject(u, &valueStatus));
triedExact = TRUE;
break;
}
UFormattableType uType = ufmt_getType(u, &status);
if(U_FAILURE(status)) {
errln("%s:%d: Error calling ufmt_getType - %s", file, line, u_errorName(status));
return FALSE;
}
if(uType != expectUType) {
errln("%s:%d: got type (%d) expected (%d) from ufmt_getType", file, line, (int) uType, (int) expectUType);
}
if(triedExact) {
if(U_FAILURE(valueStatus)) {
errln("%s:%d: got err %s trying to ufmt_get...() for exact match check", file, line, u_errorName(valueStatus));
} else if(!exactMatch) {
errln("%s:%d: failed exact match for the Formattable type", file, line);
} else {
logln("%s:%d: exact match OK", file, line);
}
} else {
logln("%s:%d: note, did not attempt exact match for this formattable type", file, line);
}
if( assertEquals(fileLine + " isNumeric()", f.isNumeric(), ufmt_isNumeric(u))
&& f.isNumeric()) {
UErrorCode convStatus = U_ZERO_ERROR;
assertTrue(fileLine + " as doubles ==", f.getDouble(convStatus)==ufmt_getDouble(u, &convStatus));
if( assertSuccess(fileLine + " (numeric conversion status)", convStatus) ) {
StringPiece fDecNum = f.getDecimalNumber(convStatus);
#if 1
int32_t len;
const char *decNumChars = ufmt_getDecNumChars(u, &len, &convStatus);
#else
// copy version
char decNumChars[200];
int32_t len = ufmt_getDecNumChars(u, decNumChars, 200, &convStatus);
#endif
if( assertSuccess(fileLine + " (decNumbers conversion)", convStatus) ) {
logln(fileLine + decNumChars);
assertEquals(fileLine + " decNumChars length==", len, fDecNum.length());
assertEquals(fileLine + " decNumChars digits", decNumChars, fDecNum.data());
}
UErrorCode int64ConversionF = U_ZERO_ERROR;
int64_t l = f.getInt64(int64ConversionF);
UErrorCode int64ConversionU = U_ZERO_ERROR;
int64_t r = ufmt_getInt64(u, &int64ConversionU);
if( (l==r)
&& ( uType != UFMT_INT64 ) // int64 better not overflow
&& (U_INVALID_FORMAT_ERROR==int64ConversionU)
&& (U_INVALID_FORMAT_ERROR==int64ConversionF) ) {
logln("%s:%d: OK: 64 bit overflow", file, line);
} else {
assertEquals(fileLine + " as int64 ==", l, r);
assertSuccess(fileLine + " Formattable.getnt64()", int64ConversionF);
assertSuccess(fileLine + " ufmt_getInt64()", int64ConversionU);
}
}
}
return exactMatch || !triedExact;
}
void NumberFormatTest::TestUFormattable(void) {
{
// test that a default formattable is equal to Formattable()
UErrorCode status = U_ZERO_ERROR;
LocalUFormattablePointer defaultUFormattable(ufmt_open(&status));
assertSuccess("calling umt_open", status);
Formattable defaultFormattable;
assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
(defaultFormattable
== *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
(defaultFormattable
== *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
assertTrue((UnicodeString)"comparing Formattable() round tripped through UFormattable",
(defaultFormattable
== *(Formattable::fromUFormattable(defaultFormattable.toUFormattable()))));
assertTrue((UnicodeString)"comparing &Formattable() round tripped through UFormattable",
((&defaultFormattable)
== Formattable::fromUFormattable(defaultFormattable.toUFormattable())));
assertFalse((UnicodeString)"comparing &Formattable() with ufmt_open()",
((&defaultFormattable)
== Formattable::fromUFormattable(defaultUFormattable.getAlias())));
testFormattableAsUFormattable(__FILE__, __LINE__, defaultFormattable);
}
// test some random Formattables
{
Formattable f(ucal_getNow(), Formattable::kIsDate);
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
Formattable f((double)1.61803398874989484820); // golden ratio
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
Formattable f((int64_t)80994231587905127LL); // weight of the moon, in kilotons http://solarsystem.nasa.gov/planets/profile.cfm?Display=Facts&Object=Moon
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
Formattable f((int32_t)4); // random number, source: http://www.xkcd.com/221/
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
Formattable f("Hello world."); // should be invariant?
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
UErrorCode status2 = U_ZERO_ERROR;
Formattable f(StringPiece("73476730924573500000000.0"), status2); // weight of the moon, kg
assertSuccess("Constructing a StringPiece", status2);
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
UErrorCode status2 = U_ZERO_ERROR;
UObject *obj = new Locale();
Formattable f(obj);
assertSuccess("Constructing a Formattable from a default constructed Locale()", status2);
testFormattableAsUFormattable(__FILE__, __LINE__, f);
}
{
const Formattable array[] = {
Formattable(ucal_getNow(), Formattable::kIsDate),
Formattable((int32_t)4),
Formattable((double)1.234),
};
Formattable fa(array, 3);
testFormattableAsUFormattable(__FILE__, __LINE__, fa);
}
}
void NumberFormatTest::TestSignificantDigits(void) {
double input[] = {
0, 0,

View File

@ -160,6 +160,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
void TestFormattableSize();
void TestUFormattable();
void TestEnumSet();
void TestSignificantDigits();
@ -169,6 +171,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
void TestBug9936();
private:
UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);
void expectParseCurrency(const NumberFormat &fmt, const UChar* currency, double amount, const char *text);
static UBool equalValue(const Formattable& a, const Formattable& b);