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