Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 1997-2010, International Business Machines Corporation and    *
      4 * others. All Rights Reserved.                                                *
      5 *******************************************************************************
      6 *
      7 * File FMTABLE.CPP
      8 *
      9 * Modification History:
     10 *
     11 *   Date        Name        Description
     12 *   03/25/97    clhuang     Initial Implementation.
     13 ********************************************************************************
     14 */
     15 
     16 #include "unicode/utypes.h"
     17 
     18 #if !UCONFIG_NO_FORMATTING
     19 
     20 #include "unicode/fmtable.h"
     21 #include "unicode/ustring.h"
     22 #include "unicode/measure.h"
     23 #include "unicode/curramt.h"
     24 #include "charstr.h"
     25 #include "cmemory.h"
     26 #include "cstring.h"
     27 #include "decNumber.h"
     28 #include "digitlst.h"
     29 
     30 // *****************************************************************************
     31 // class Formattable
     32 // *****************************************************************************
     33 
     34 U_NAMESPACE_BEGIN
     35 
     36 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
     37 
     38 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
     39 
     40 // NOTE: As of 3.0, there are limitations to the UObject API.  It does
     41 // not (yet) support cloning, operator=, nor operator==.  To
     42 // work around this, I implement some simple inlines here.  Later
     43 // these can be modified or removed.  [alan]
     44 
     45 // NOTE: These inlines assume that all fObjects are in fact instances
     46 // of the Measure class, which is true as of 3.0.  [alan]
     47 
     48 // Return TRUE if *a == *b.
     49 static inline UBool objectEquals(const UObject* a, const UObject* b) {
     50     // LATER: return *a == *b;
     51     return *((const Measure*) a) == *((const Measure*) b);
     52 }
     53 
     54 // Return a clone of *a.
     55 static inline UObject* objectClone(const UObject* a) {
     56     // LATER: return a->clone();
     57     return ((const Measure*) a)->clone();
     58 }
     59 
     60 // Return TRUE if *a is an instance of Measure.
     61 static inline UBool instanceOfMeasure(const UObject* a) {
     62     // BEGIN android-changed : no RTTI support
     63     // return dynamic_cast<const Measure*>(a) != NULL;
     64     return (const Measure*)a != NULL;
     65     // END android-changed
     66 }
     67 
     68 /**
     69  * Creates a new Formattable array and copies the values from the specified
     70  * original.
     71  * @param array the original array
     72  * @param count the original array count
     73  * @return the new Formattable array.
     74  */
     75 static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
     76     Formattable *result = new Formattable[count];
     77     if (result != NULL) {
     78         for (int32_t i=0; i<count; ++i)
     79             result[i] = array[i]; // Don't memcpy!
     80     }
     81     return result;
     82 }
     83 
     84 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
     85 
     86 /**
     87  * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
     88  */
     89 static void setError(UErrorCode& ec, UErrorCode err) {
     90     if (U_SUCCESS(ec)) {
     91         ec = err;
     92     }
     93 }
     94 
     95 //
     96 //  Common initialization code, shared by constructors.
     97 //  Put everything into a known state.
     98 //
     99 void  Formattable::init() {
    100     fValue.fInt64 = 0;
    101     fType = kLong;
    102     fDecimalStr = NULL;
    103     fDecimalNum = NULL;
    104     fBogus.setToBogus();
    105 }
    106 
    107 // -------------------------------------
    108 // default constructor.
    109 // Creates a formattable object with a long value 0.
    110 
    111 Formattable::Formattable() {
    112     init();
    113 }
    114 
    115 // -------------------------------------
    116 // Creates a formattable object with a Date instance.
    117 
    118 Formattable::Formattable(UDate date, ISDATE /*isDate*/)
    119 {
    120     init();
    121     fType = kDate;
    122     fValue.fDate = date;
    123 }
    124 
    125 // -------------------------------------
    126 // Creates a formattable object with a double value.
    127 
    128 Formattable::Formattable(double value)
    129 {
    130     init();
    131     fType = kDouble;
    132     fValue.fDouble = value;
    133 }
    134 
    135 // -------------------------------------
    136 // Creates a formattable object with an int32_t value.
    137 
    138 Formattable::Formattable(int32_t value)
    139 {
    140     init();
    141     fValue.fInt64 = value;
    142 }
    143 
    144 // -------------------------------------
    145 // Creates a formattable object with an int64_t value.
    146 
    147 Formattable::Formattable(int64_t value)
    148 {
    149     init();
    150     fType = kInt64;
    151     fValue.fInt64 = value;
    152 }
    153 
    154 // -------------------------------------
    155 // Creates a formattable object with a decimal number value from a string.
    156 
    157 Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
    158     init();
    159     setDecimalNumber(number, status);
    160 }
    161 
    162 
    163 // -------------------------------------
    164 // Creates a formattable object with a UnicodeString instance.
    165 
    166 Formattable::Formattable(const UnicodeString& stringToCopy)
    167 {
    168     init();
    169     fType = kString;
    170     fValue.fString = new UnicodeString(stringToCopy);
    171 }
    172 
    173 // -------------------------------------
    174 // Creates a formattable object with a UnicodeString* value.
    175 // (adopting symantics)
    176 
    177 Formattable::Formattable(UnicodeString* stringToAdopt)
    178 {
    179     init();
    180     fType = kString;
    181     fValue.fString = stringToAdopt;
    182 }
    183 
    184 Formattable::Formattable(UObject* objectToAdopt)
    185 {
    186     init();
    187     fType = kObject;
    188     fValue.fObject = objectToAdopt;
    189 }
    190 
    191 // -------------------------------------
    192 
    193 Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
    194     :   UObject(), fType(kArray)
    195 {
    196     init();
    197     fType = kArray;
    198     fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
    199     fValue.fArrayAndCount.fCount = count;
    200 }
    201 
    202 // -------------------------------------
    203 // copy constructor
    204 
    205 
    206 Formattable::Formattable(const Formattable &source)
    207      :  UObject(*this)
    208 {
    209     init();
    210     *this = source;
    211 }
    212 
    213 // -------------------------------------
    214 // assignment operator
    215 
    216 Formattable&
    217 Formattable::operator=(const Formattable& source)
    218 {
    219     if (this != &source)
    220     {
    221         // Disposes the current formattable value/setting.
    222         dispose();
    223 
    224         // Sets the correct data type for this value.
    225         fType = source.fType;
    226         switch (fType)
    227         {
    228         case kArray:
    229             // Sets each element in the array one by one and records the array count.
    230             fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
    231             fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
    232                                                            source.fValue.fArrayAndCount.fCount);
    233             break;
    234         case kString:
    235             // Sets the string value.
    236             fValue.fString = new UnicodeString(*source.fValue.fString);
    237             break;
    238         case kDouble:
    239             // Sets the double value.
    240             fValue.fDouble = source.fValue.fDouble;
    241             break;
    242         case kLong:
    243         case kInt64:
    244             // Sets the long value.
    245             fValue.fInt64 = source.fValue.fInt64;
    246             break;
    247         case kDate:
    248             // Sets the Date value.
    249             fValue.fDate = source.fValue.fDate;
    250             break;
    251         case kObject:
    252             fValue.fObject = objectClone(source.fValue.fObject);
    253             break;
    254         }
    255 
    256         UErrorCode status = U_ZERO_ERROR;
    257         if (source.fDecimalNum != NULL) {
    258             fDecimalNum = new DigitList(*source.fDecimalNum);
    259         }
    260         if (source.fDecimalStr != NULL) {
    261             fDecimalStr = new CharString(*source.fDecimalStr, status);
    262             if (U_FAILURE(status)) {
    263                 delete fDecimalStr;
    264                 fDecimalStr = NULL;
    265             }
    266         }
    267     }
    268     return *this;
    269 }
    270 
    271 // -------------------------------------
    272 
    273 UBool
    274 Formattable::operator==(const Formattable& that) const
    275 {
    276     int32_t i;
    277 
    278     if (this == &that) return TRUE;
    279 
    280     // Returns FALSE if the data types are different.
    281     if (fType != that.fType) return FALSE;
    282 
    283     // Compares the actual data values.
    284     UBool equal = TRUE;
    285     switch (fType) {
    286     case kDate:
    287         equal = (fValue.fDate == that.fValue.fDate);
    288         break;
    289     case kDouble:
    290         equal = (fValue.fDouble == that.fValue.fDouble);
    291         break;
    292     case kLong:
    293     case kInt64:
    294         equal = (fValue.fInt64 == that.fValue.fInt64);
    295         break;
    296     case kString:
    297         equal = (*(fValue.fString) == *(that.fValue.fString));
    298         break;
    299     case kArray:
    300         if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
    301             equal = FALSE;
    302             break;
    303         }
    304         // Checks each element for equality.
    305         for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
    306             if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
    307                 equal = FALSE;
    308                 break;
    309             }
    310         }
    311         break;
    312     case kObject:
    313         if (fValue.fObject == NULL || that.fValue.fObject == NULL) {
    314             equal = FALSE;
    315         } else {
    316             equal = objectEquals(fValue.fObject, that.fValue.fObject);
    317         }
    318         break;
    319     }
    320 
    321     // TODO:  compare digit lists if numeric.
    322     return equal;
    323 }
    324 
    325 // -------------------------------------
    326 
    327 Formattable::~Formattable()
    328 {
    329     dispose();
    330 }
    331 
    332 // -------------------------------------
    333 
    334 void Formattable::dispose()
    335 {
    336     // Deletes the data value if necessary.
    337     switch (fType) {
    338     case kString:
    339         delete fValue.fString;
    340         break;
    341     case kArray:
    342         delete[] fValue.fArrayAndCount.fArray;
    343         break;
    344     case kObject:
    345         delete fValue.fObject;
    346         break;
    347     default:
    348         break;
    349     }
    350 
    351     fType = kLong;
    352     fValue.fInt64 = 0;
    353     delete fDecimalStr;
    354     fDecimalStr = NULL;
    355     delete fDecimalNum;
    356     fDecimalNum = NULL;
    357 }
    358 
    359 Formattable *
    360 Formattable::clone() const {
    361     return new Formattable(*this);
    362 }
    363 
    364 // -------------------------------------
    365 // Gets the data type of this Formattable object.
    366 Formattable::Type
    367 Formattable::getType() const
    368 {
    369     return fType;
    370 }
    371 
    372 UBool
    373 Formattable::isNumeric() const {
    374     switch (fType) {
    375     case kDouble:
    376     case kLong:
    377     case kInt64:
    378         return TRUE;
    379     default:
    380         return FALSE;
    381     }
    382 }
    383 
    384 // -------------------------------------
    385 int32_t
    386 //Formattable::getLong(UErrorCode* status) const
    387 Formattable::getLong(UErrorCode& status) const
    388 {
    389     if (U_FAILURE(status)) {
    390         return 0;
    391     }
    392 
    393     switch (fType) {
    394     case Formattable::kLong:
    395         return (int32_t)fValue.fInt64;
    396     case Formattable::kInt64:
    397         if (fValue.fInt64 > INT32_MAX) {
    398             status = U_INVALID_FORMAT_ERROR;
    399             return INT32_MAX;
    400         } else if (fValue.fInt64 < INT32_MIN) {
    401             status = U_INVALID_FORMAT_ERROR;
    402             return INT32_MIN;
    403         } else {
    404             return (int32_t)fValue.fInt64;
    405         }
    406     case Formattable::kDouble:
    407         if (fValue.fDouble > INT32_MAX) {
    408             status = U_INVALID_FORMAT_ERROR;
    409             return INT32_MAX;
    410         } else if (fValue.fDouble < INT32_MIN) {
    411             status = U_INVALID_FORMAT_ERROR;
    412             return INT32_MIN;
    413         } else {
    414             return (int32_t)fValue.fDouble; // loses fraction
    415         }
    416     case Formattable::kObject:
    417         if (fValue.fObject == NULL) {
    418             status = U_MEMORY_ALLOCATION_ERROR;
    419             return 0;
    420         }
    421         // TODO Later replace this with instanceof call
    422         if (instanceOfMeasure(fValue.fObject)) {
    423             return ((const Measure*) fValue.fObject)->
    424                 getNumber().getLong(status);
    425         }
    426     default:
    427         status = U_INVALID_FORMAT_ERROR;
    428         return 0;
    429     }
    430 }
    431 
    432 // -------------------------------------
    433 int64_t
    434 Formattable::getInt64(UErrorCode& status) const
    435 {
    436     if (U_FAILURE(status)) {
    437         return 0;
    438     }
    439 
    440     switch (fType) {
    441     case Formattable::kLong:
    442     case Formattable::kInt64:
    443         return fValue.fInt64;
    444     case Formattable::kDouble:
    445         if (fValue.fDouble >= U_INT64_MAX) {
    446             status = U_INVALID_FORMAT_ERROR;
    447             return U_INT64_MAX;
    448         } else if (fValue.fDouble <= U_INT64_MIN) {
    449             status = U_INVALID_FORMAT_ERROR;
    450             return U_INT64_MIN;
    451         } else {
    452             return (int64_t)fValue.fDouble;
    453         }
    454     case Formattable::kObject:
    455         if (fValue.fObject == NULL) {
    456             status = U_MEMORY_ALLOCATION_ERROR;
    457             return 0;
    458         }
    459         // TODO Later replace this with instanceof call
    460         if (instanceOfMeasure(fValue.fObject)) {
    461             return ((const Measure*) fValue.fObject)->
    462                 getNumber().getInt64(status);
    463         }
    464     default:
    465         status = U_INVALID_FORMAT_ERROR;
    466         return 0;
    467     }
    468 }
    469 
    470 // -------------------------------------
    471 double
    472 Formattable::getDouble(UErrorCode& status) const
    473 {
    474     if (U_FAILURE(status)) {
    475         return 0;
    476     }
    477 
    478     switch (fType) {
    479     case Formattable::kLong:
    480     case Formattable::kInt64: // loses precision
    481         return (double)fValue.fInt64;
    482     case Formattable::kDouble:
    483         return fValue.fDouble;
    484     case Formattable::kObject:
    485         if (fValue.fObject == NULL) {
    486             status = U_MEMORY_ALLOCATION_ERROR;
    487             return 0;
    488         }
    489         // TODO Later replace this with instanceof call
    490         if (instanceOfMeasure(fValue.fObject)) {
    491             return ((const Measure*) fValue.fObject)->
    492                 getNumber().getDouble(status);
    493         }
    494     default:
    495         status = U_INVALID_FORMAT_ERROR;
    496         return 0;
    497     }
    498 }
    499 
    500 const UObject*
    501 Formattable::getObject() const {
    502     return (fType == kObject) ? fValue.fObject : NULL;
    503 }
    504 
    505 // -------------------------------------
    506 // Sets the value to a double value d.
    507 
    508 void
    509 Formattable::setDouble(double d)
    510 {
    511     dispose();
    512     fType = kDouble;
    513     fValue.fDouble = d;
    514 }
    515 
    516 // -------------------------------------
    517 // Sets the value to a long value l.
    518 
    519 void
    520 Formattable::setLong(int32_t l)
    521 {
    522     dispose();
    523     fType = kLong;
    524     fValue.fInt64 = l;
    525 }
    526 
    527 // -------------------------------------
    528 // Sets the value to an int64 value ll.
    529 
    530 void
    531 Formattable::setInt64(int64_t ll)
    532 {
    533     dispose();
    534     fType = kInt64;
    535     fValue.fInt64 = ll;
    536 }
    537 
    538 // -------------------------------------
    539 // Sets the value to a Date instance d.
    540 
    541 void
    542 Formattable::setDate(UDate d)
    543 {
    544     dispose();
    545     fType = kDate;
    546     fValue.fDate = d;
    547 }
    548 
    549 // -------------------------------------
    550 // Sets the value to a string value stringToCopy.
    551 
    552 void
    553 Formattable::setString(const UnicodeString& stringToCopy)
    554 {
    555     dispose();
    556     fType = kString;
    557     fValue.fString = new UnicodeString(stringToCopy);
    558 }
    559 
    560 // -------------------------------------
    561 // Sets the value to an array of Formattable objects.
    562 
    563 void
    564 Formattable::setArray(const Formattable* array, int32_t count)
    565 {
    566     dispose();
    567     fType = kArray;
    568     fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
    569     fValue.fArrayAndCount.fCount = count;
    570 }
    571 
    572 // -------------------------------------
    573 // Adopts the stringToAdopt value.
    574 
    575 void
    576 Formattable::adoptString(UnicodeString* stringToAdopt)
    577 {
    578     dispose();
    579     fType = kString;
    580     fValue.fString = stringToAdopt;
    581 }
    582 
    583 // -------------------------------------
    584 // Adopts the array value and its count.
    585 
    586 void
    587 Formattable::adoptArray(Formattable* array, int32_t count)
    588 {
    589     dispose();
    590     fType = kArray;
    591     fValue.fArrayAndCount.fArray = array;
    592     fValue.fArrayAndCount.fCount = count;
    593 }
    594 
    595 void
    596 Formattable::adoptObject(UObject* objectToAdopt) {
    597     dispose();
    598     fType = kObject;
    599     fValue.fObject = objectToAdopt;
    600 }
    601 
    602 // -------------------------------------
    603 UnicodeString&
    604 Formattable::getString(UnicodeString& result, UErrorCode& status) const
    605 {
    606     if (fType != kString) {
    607         setError(status, U_INVALID_FORMAT_ERROR);
    608         result.setToBogus();
    609     } else {
    610         if (fValue.fString == NULL) {
    611             setError(status, U_MEMORY_ALLOCATION_ERROR);
    612         } else {
    613             result = *fValue.fString;
    614         }
    615     }
    616     return result;
    617 }
    618 
    619 // -------------------------------------
    620 const UnicodeString&
    621 Formattable::getString(UErrorCode& status) const
    622 {
    623     if (fType != kString) {
    624         setError(status, U_INVALID_FORMAT_ERROR);
    625         return *getBogus();
    626     }
    627     if (fValue.fString == NULL) {
    628         setError(status, U_MEMORY_ALLOCATION_ERROR);
    629         return *getBogus();
    630     }
    631     return *fValue.fString;
    632 }
    633 
    634 // -------------------------------------
    635 UnicodeString&
    636 Formattable::getString(UErrorCode& status)
    637 {
    638     if (fType != kString) {
    639         setError(status, U_INVALID_FORMAT_ERROR);
    640         return *getBogus();
    641     }
    642     if (fValue.fString == NULL) {
    643     	setError(status, U_MEMORY_ALLOCATION_ERROR);
    644     	return *getBogus();
    645     }
    646     return *fValue.fString;
    647 }
    648 
    649 // -------------------------------------
    650 const Formattable*
    651 Formattable::getArray(int32_t& count, UErrorCode& status) const
    652 {
    653     if (fType != kArray) {
    654         setError(status, U_INVALID_FORMAT_ERROR);
    655         count = 0;
    656         return NULL;
    657     }
    658     count = fValue.fArrayAndCount.fCount;
    659     return fValue.fArrayAndCount.fArray;
    660 }
    661 
    662 // -------------------------------------
    663 // Gets the bogus string, ensures mondo bogosity.
    664 
    665 UnicodeString*
    666 Formattable::getBogus() const
    667 {
    668     return (UnicodeString*)&fBogus; /* cast away const :-( */
    669 }
    670 
    671 
    672 // --------------------------------------
    673 StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
    674     if (U_FAILURE(status)) {
    675         return "";
    676     }
    677     if (fDecimalStr != NULL) {
    678         return fDecimalStr->toStringPiece();
    679     }
    680 
    681     if (fDecimalNum == NULL) {
    682         // No decimal number for the formattable yet.  Which means the value was
    683         // set directly by the user as an int, int64 or double.  If the value came
    684         // from parsing, or from the user setting a decimal number, fDecimalNum
    685         // would already be set.
    686         //
    687         fDecimalNum = new DigitList;
    688         if (fDecimalNum == NULL) {
    689             status = U_MEMORY_ALLOCATION_ERROR;
    690             return "";
    691         }
    692 
    693         switch (fType) {
    694         case kDouble:
    695             fDecimalNum->set(this->getDouble());
    696             break;
    697         case kLong:
    698             fDecimalNum->set(this->getLong());
    699             break;
    700         case kInt64:
    701             fDecimalNum->set(this->getInt64());
    702             break;
    703         default:
    704             // The formattable's value is not a numeric type.
    705             status = U_INVALID_STATE_ERROR;
    706             return "";
    707         }
    708     }
    709 
    710     fDecimalStr = new CharString;
    711     if (fDecimalStr == NULL) {
    712         status = U_MEMORY_ALLOCATION_ERROR;
    713         return "";
    714     }
    715     fDecimalNum->getDecimal(*fDecimalStr, status);
    716 
    717     return fDecimalStr->toStringPiece();
    718 }
    719 
    720 
    721 
    722 // ---------------------------------------
    723 void
    724 Formattable::adoptDigitList(DigitList *dl) {
    725     dispose();
    726 
    727     fDecimalNum = dl;
    728 
    729     // Set the value into the Union of simple type values.
    730     // Cannot use the set() functions because they would delete the fDecimalNum value,
    731 
    732     if (fDecimalNum->fitsIntoLong(FALSE)) {
    733         fType = kLong;
    734         fValue.fInt64 = fDecimalNum->getLong();
    735     } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
    736         fType = kInt64;
    737         fValue.fInt64 = fDecimalNum->getInt64();
    738     } else {
    739         fType = kDouble;
    740         fValue.fDouble = fDecimalNum->getDouble();
    741     }
    742 }
    743 
    744 
    745 // ---------------------------------------
    746 void
    747 Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
    748     if (U_FAILURE(status)) {
    749         return;
    750     }
    751     dispose();
    752 
    753     // Copy the input string and nul-terminate it.
    754     //    The decNumber library requires nul-terminated input.  StringPiece input
    755     //    is not guaranteed nul-terminated.  Too bad.
    756     //    CharString automatically adds the nul.
    757     DigitList *dnum = new DigitList();
    758     if (dnum == NULL) {
    759         status = U_MEMORY_ALLOCATION_ERROR;
    760         return;
    761     }
    762     dnum->set(CharString(numberString, status).toStringPiece(), status);
    763     if (U_FAILURE(status)) {
    764         delete dnum;
    765         return;   // String didn't contain a decimal number.
    766     }
    767     adoptDigitList(dnum);
    768 
    769     // Note that we do not hang on to the caller's input string.
    770     // If we are asked for the string, we will regenerate one from fDecimalNum.
    771 }
    772 
    773 #if 0
    774 //----------------------------------------------------
    775 // console I/O
    776 //----------------------------------------------------
    777 #ifdef _DEBUG
    778 
    779 #if U_IOSTREAM_SOURCE >= 199711
    780 #include <iostream>
    781 using namespace std;
    782 #elif U_IOSTREAM_SOURCE >= 198506
    783 #include <iostream.h>
    784 #endif
    785 
    786 #include "unicode/datefmt.h"
    787 #include "unistrm.h"
    788 
    789 class FormattableStreamer /* not : public UObject because all methods are static */ {
    790 public:
    791     static void streamOut(ostream& stream, const Formattable& obj);
    792 
    793 private:
    794     FormattableStreamer() {} // private - forbid instantiation
    795 };
    796 
    797 // This is for debugging purposes only.  This will send a displayable
    798 // form of the Formattable object to the output stream.
    799 
    800 void
    801 FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
    802 {
    803     static DateFormat *defDateFormat = 0;
    804 
    805     UnicodeString buffer;
    806     switch(obj.getType()) {
    807         case Formattable::kDate :
    808             // Creates a DateFormat instance for formatting the
    809             // Date instance.
    810             if (defDateFormat == 0) {
    811                 defDateFormat = DateFormat::createInstance();
    812             }
    813             defDateFormat->format(obj.getDate(), buffer);
    814             stream << buffer;
    815             break;
    816         case Formattable::kDouble :
    817             // Output the double as is.
    818             stream << obj.getDouble() << 'D';
    819             break;
    820         case Formattable::kLong :
    821             // Output the double as is.
    822             stream << obj.getLong() << 'L';
    823             break;
    824         case Formattable::kString:
    825             // Output the double as is.  Please see UnicodeString console
    826             // I/O routine for more details.
    827             stream << '"' << obj.getString(buffer) << '"';
    828             break;
    829         case Formattable::kArray:
    830             int32_t i, count;
    831             const Formattable* array;
    832             array = obj.getArray(count);
    833             stream << '[';
    834             // Recursively calling the console I/O routine for each element in the array.
    835             for (i=0; i<count; ++i) {
    836                 FormattableStreamer::streamOut(stream, array[i]);
    837                 stream << ( (i==(count-1)) ? "" : ", " );
    838             }
    839             stream << ']';
    840             break;
    841         default:
    842             // Not a recognizable Formattable object.
    843             stream << "INVALID_Formattable";
    844     }
    845     stream.flush();
    846 }
    847 #endif
    848 
    849 #endif
    850 
    851 U_NAMESPACE_END
    852 
    853 #endif /* #if !UCONFIG_NO_FORMATTING */
    854 
    855 //eof
    856