• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)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.
objectClone(const UObject * 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.
instanceOfMeasure(const UObject * a)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  */
createArrayCopy(const Formattable * array,int32_t count)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  */
setError(UErrorCode & ec,UErrorCode err)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 //
init()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 
Formattable()111 Formattable::Formattable() {
112     init();
113 }
114 
115 // -------------------------------------
116 // Creates a formattable object with a Date instance.
117 
Formattable(UDate date,ISDATE)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 
Formattable(double value)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 
Formattable(int32_t value)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 
Formattable(int64_t value)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 
Formattable(const StringPiece & number,UErrorCode & status)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 
Formattable(const UnicodeString & stringToCopy)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 
Formattable(UnicodeString * stringToAdopt)177 Formattable::Formattable(UnicodeString* stringToAdopt)
178 {
179     init();
180     fType = kString;
181     fValue.fString = stringToAdopt;
182 }
183 
Formattable(UObject * objectToAdopt)184 Formattable::Formattable(UObject* objectToAdopt)
185 {
186     init();
187     fType = kObject;
188     fValue.fObject = objectToAdopt;
189 }
190 
191 // -------------------------------------
192 
Formattable(const Formattable * arrayToCopy,int32_t count)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 
Formattable(const Formattable & source)206 Formattable::Formattable(const Formattable &source)
207      :  UObject(*this)
208 {
209     init();
210     *this = source;
211 }
212 
213 // -------------------------------------
214 // assignment operator
215 
216 Formattable&
operator =(const Formattable & source)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
operator ==(const Formattable & that) const274 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 
~Formattable()327 Formattable::~Formattable()
328 {
329     dispose();
330 }
331 
332 // -------------------------------------
333 
dispose()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 *
clone() const360 Formattable::clone() const {
361     return new Formattable(*this);
362 }
363 
364 // -------------------------------------
365 // Gets the data type of this Formattable object.
366 Formattable::Type
getType() const367 Formattable::getType() const
368 {
369     return fType;
370 }
371 
372 UBool
isNumeric() const373 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
getLong(UErrorCode & status) const387 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
getInt64(UErrorCode & status) const434 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
getDouble(UErrorCode & status) const472 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*
getObject() const501 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
setDouble(double d)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
setLong(int32_t l)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
setInt64(int64_t ll)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
setDate(UDate d)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
setString(const UnicodeString & stringToCopy)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
setArray(const Formattable * array,int32_t count)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
adoptString(UnicodeString * stringToAdopt)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
adoptArray(Formattable * array,int32_t count)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
adoptObject(UObject * objectToAdopt)596 Formattable::adoptObject(UObject* objectToAdopt) {
597     dispose();
598     fType = kObject;
599     fValue.fObject = objectToAdopt;
600 }
601 
602 // -------------------------------------
603 UnicodeString&
getString(UnicodeString & result,UErrorCode & status) const604 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&
getString(UErrorCode & status) const621 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&
getString(UErrorCode & status)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*
getArray(int32_t & count,UErrorCode & status) const651 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*
getBogus() const666 Formattable::getBogus() const
667 {
668     return (UnicodeString*)&fBogus; /* cast away const :-( */
669 }
670 
671 
672 // --------------------------------------
getDecimalNumber(UErrorCode & status)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
adoptDigitList(DigitList * dl)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
setDecimalNumber(const StringPiece & numberString,UErrorCode & status)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