]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/fmtable.cpp
ICU-511.25.tar.gz
[apple/icu.git] / icuSources / i18n / fmtable.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2012, 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
37 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
38
39 #include "fmtableimp.h"
40
41 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
42
43 // NOTE: As of 3.0, there are limitations to the UObject API. It does
44 // not (yet) support cloning, operator=, nor operator==. To
45 // work around this, I implement some simple inlines here. Later
46 // these can be modified or removed. [alan]
47
48 // NOTE: These inlines assume that all fObjects are in fact instances
49 // of the Measure class, which is true as of 3.0. [alan]
50
51 // Return TRUE if *a == *b.
52 static inline UBool objectEquals(const UObject* a, const UObject* b) {
53 // LATER: return *a == *b;
54 return *((const Measure*) a) == *((const Measure*) b);
55 }
56
57 // Return a clone of *a.
58 static inline UObject* objectClone(const UObject* a) {
59 // LATER: return a->clone();
60 return ((const Measure*) a)->clone();
61 }
62
63 // Return TRUE if *a is an instance of Measure.
64 static inline UBool instanceOfMeasure(const UObject* a) {
65 return dynamic_cast<const Measure*>(a) != NULL;
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); // TODO: use internal digit list
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
354 delete fDecimalStr;
355 fDecimalStr = NULL;
356
357 FmtStackData *stackData = (FmtStackData*)fStackData;
358 if(fDecimalNum != &(stackData->stackDecimalNum)) {
359 delete fDecimalNum;
360 } else {
361 fDecimalNum->~DigitList(); // destruct, don't deallocate
362 }
363 fDecimalNum = NULL;
364 }
365
366 Formattable *
367 Formattable::clone() const {
368 return new Formattable(*this);
369 }
370
371 // -------------------------------------
372 // Gets the data type of this Formattable object.
373 Formattable::Type
374 Formattable::getType() const
375 {
376 return fType;
377 }
378
379 UBool
380 Formattable::isNumeric() const {
381 switch (fType) {
382 case kDouble:
383 case kLong:
384 case kInt64:
385 return TRUE;
386 default:
387 return FALSE;
388 }
389 }
390
391 // -------------------------------------
392 int32_t
393 //Formattable::getLong(UErrorCode* status) const
394 Formattable::getLong(UErrorCode& status) const
395 {
396 if (U_FAILURE(status)) {
397 return 0;
398 }
399
400 switch (fType) {
401 case Formattable::kLong:
402 return (int32_t)fValue.fInt64;
403 case Formattable::kInt64:
404 if (fValue.fInt64 > INT32_MAX) {
405 status = U_INVALID_FORMAT_ERROR;
406 return INT32_MAX;
407 } else if (fValue.fInt64 < INT32_MIN) {
408 status = U_INVALID_FORMAT_ERROR;
409 return INT32_MIN;
410 } else {
411 return (int32_t)fValue.fInt64;
412 }
413 case Formattable::kDouble:
414 if (fValue.fDouble > INT32_MAX) {
415 status = U_INVALID_FORMAT_ERROR;
416 return INT32_MAX;
417 } else if (fValue.fDouble < INT32_MIN) {
418 status = U_INVALID_FORMAT_ERROR;
419 return INT32_MIN;
420 } else {
421 return (int32_t)fValue.fDouble; // loses fraction
422 }
423 case Formattable::kObject:
424 if (fValue.fObject == NULL) {
425 status = U_MEMORY_ALLOCATION_ERROR;
426 return 0;
427 }
428 // TODO Later replace this with instanceof call
429 if (instanceOfMeasure(fValue.fObject)) {
430 return ((const Measure*) fValue.fObject)->
431 getNumber().getLong(status);
432 }
433 default:
434 status = U_INVALID_FORMAT_ERROR;
435 return 0;
436 }
437 }
438
439 // -------------------------------------
440 // Maximum int that can be represented exactly in a double. (53 bits)
441 // Larger ints may be rounded to a near-by value as not all are representable.
442 // TODO: move this constant elsewhere, possibly configure it for different
443 // floating point formats, if any non-standard ones are still in use.
444 static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL;
445
446 int64_t
447 Formattable::getInt64(UErrorCode& status) const
448 {
449 if (U_FAILURE(status)) {
450 return 0;
451 }
452
453 switch (fType) {
454 case Formattable::kLong:
455 case Formattable::kInt64:
456 return fValue.fInt64;
457 case Formattable::kDouble:
458 if (fValue.fDouble > (double)U_INT64_MAX) {
459 status = U_INVALID_FORMAT_ERROR;
460 return U_INT64_MAX;
461 } else if (fValue.fDouble < (double)U_INT64_MIN) {
462 status = U_INVALID_FORMAT_ERROR;
463 return U_INT64_MIN;
464 } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) {
465 int64_t val = fDecimalNum->getInt64();
466 if (val != 0) {
467 return val;
468 } else {
469 status = U_INVALID_FORMAT_ERROR;
470 return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN;
471 }
472 } else {
473 return (int64_t)fValue.fDouble;
474 }
475 case Formattable::kObject:
476 if (fValue.fObject == NULL) {
477 status = U_MEMORY_ALLOCATION_ERROR;
478 return 0;
479 }
480 if (instanceOfMeasure(fValue.fObject)) {
481 return ((const Measure*) fValue.fObject)->
482 getNumber().getInt64(status);
483 }
484 default:
485 status = U_INVALID_FORMAT_ERROR;
486 return 0;
487 }
488 }
489
490 // -------------------------------------
491 double
492 Formattable::getDouble(UErrorCode& status) const
493 {
494 if (U_FAILURE(status)) {
495 return 0;
496 }
497
498 switch (fType) {
499 case Formattable::kLong:
500 case Formattable::kInt64: // loses precision
501 return (double)fValue.fInt64;
502 case Formattable::kDouble:
503 return fValue.fDouble;
504 case Formattable::kObject:
505 if (fValue.fObject == NULL) {
506 status = U_MEMORY_ALLOCATION_ERROR;
507 return 0;
508 }
509 // TODO Later replace this with instanceof call
510 if (instanceOfMeasure(fValue.fObject)) {
511 return ((const Measure*) fValue.fObject)->
512 getNumber().getDouble(status);
513 }
514 default:
515 status = U_INVALID_FORMAT_ERROR;
516 return 0;
517 }
518 }
519
520 const UObject*
521 Formattable::getObject() const {
522 return (fType == kObject) ? fValue.fObject : NULL;
523 }
524
525 // -------------------------------------
526 // Sets the value to a double value d.
527
528 void
529 Formattable::setDouble(double d)
530 {
531 dispose();
532 fType = kDouble;
533 fValue.fDouble = d;
534 }
535
536 // -------------------------------------
537 // Sets the value to a long value l.
538
539 void
540 Formattable::setLong(int32_t l)
541 {
542 dispose();
543 fType = kLong;
544 fValue.fInt64 = l;
545 }
546
547 // -------------------------------------
548 // Sets the value to an int64 value ll.
549
550 void
551 Formattable::setInt64(int64_t ll)
552 {
553 dispose();
554 fType = kInt64;
555 fValue.fInt64 = ll;
556 }
557
558 // -------------------------------------
559 // Sets the value to a Date instance d.
560
561 void
562 Formattable::setDate(UDate d)
563 {
564 dispose();
565 fType = kDate;
566 fValue.fDate = d;
567 }
568
569 // -------------------------------------
570 // Sets the value to a string value stringToCopy.
571
572 void
573 Formattable::setString(const UnicodeString& stringToCopy)
574 {
575 dispose();
576 fType = kString;
577 fValue.fString = new UnicodeString(stringToCopy);
578 }
579
580 // -------------------------------------
581 // Sets the value to an array of Formattable objects.
582
583 void
584 Formattable::setArray(const Formattable* array, int32_t count)
585 {
586 dispose();
587 fType = kArray;
588 fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
589 fValue.fArrayAndCount.fCount = count;
590 }
591
592 // -------------------------------------
593 // Adopts the stringToAdopt value.
594
595 void
596 Formattable::adoptString(UnicodeString* stringToAdopt)
597 {
598 dispose();
599 fType = kString;
600 fValue.fString = stringToAdopt;
601 }
602
603 // -------------------------------------
604 // Adopts the array value and its count.
605
606 void
607 Formattable::adoptArray(Formattable* array, int32_t count)
608 {
609 dispose();
610 fType = kArray;
611 fValue.fArrayAndCount.fArray = array;
612 fValue.fArrayAndCount.fCount = count;
613 }
614
615 void
616 Formattable::adoptObject(UObject* objectToAdopt) {
617 dispose();
618 fType = kObject;
619 fValue.fObject = objectToAdopt;
620 }
621
622 // -------------------------------------
623 UnicodeString&
624 Formattable::getString(UnicodeString& result, UErrorCode& status) const
625 {
626 if (fType != kString) {
627 setError(status, U_INVALID_FORMAT_ERROR);
628 result.setToBogus();
629 } else {
630 if (fValue.fString == NULL) {
631 setError(status, U_MEMORY_ALLOCATION_ERROR);
632 } else {
633 result = *fValue.fString;
634 }
635 }
636 return result;
637 }
638
639 // -------------------------------------
640 const UnicodeString&
641 Formattable::getString(UErrorCode& status) const
642 {
643 if (fType != kString) {
644 setError(status, U_INVALID_FORMAT_ERROR);
645 return *getBogus();
646 }
647 if (fValue.fString == NULL) {
648 setError(status, U_MEMORY_ALLOCATION_ERROR);
649 return *getBogus();
650 }
651 return *fValue.fString;
652 }
653
654 // -------------------------------------
655 UnicodeString&
656 Formattable::getString(UErrorCode& status)
657 {
658 if (fType != kString) {
659 setError(status, U_INVALID_FORMAT_ERROR);
660 return *getBogus();
661 }
662 if (fValue.fString == NULL) {
663 setError(status, U_MEMORY_ALLOCATION_ERROR);
664 return *getBogus();
665 }
666 return *fValue.fString;
667 }
668
669 // -------------------------------------
670 const Formattable*
671 Formattable::getArray(int32_t& count, UErrorCode& status) const
672 {
673 if (fType != kArray) {
674 setError(status, U_INVALID_FORMAT_ERROR);
675 count = 0;
676 return NULL;
677 }
678 count = fValue.fArrayAndCount.fCount;
679 return fValue.fArrayAndCount.fArray;
680 }
681
682 // -------------------------------------
683 // Gets the bogus string, ensures mondo bogosity.
684
685 UnicodeString*
686 Formattable::getBogus() const
687 {
688 return (UnicodeString*)&fBogus; /* cast away const :-( */
689 }
690
691
692 // --------------------------------------
693 StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
694 if (U_FAILURE(status)) {
695 return "";
696 }
697 if (fDecimalStr != NULL) {
698 return fDecimalStr->toStringPiece();
699 }
700
701 if (fDecimalNum == NULL) {
702 // No decimal number for the formattable yet. Which means the value was
703 // set directly by the user as an int, int64 or double. If the value came
704 // from parsing, or from the user setting a decimal number, fDecimalNum
705 // would already be set.
706 //
707 fDecimalNum = new DigitList; // TODO: use internal digit list
708 if (fDecimalNum == NULL) {
709 status = U_MEMORY_ALLOCATION_ERROR;
710 return "";
711 }
712
713 switch (fType) {
714 case kDouble:
715 fDecimalNum->set(this->getDouble());
716 break;
717 case kLong:
718 fDecimalNum->set(this->getLong());
719 break;
720 case kInt64:
721 fDecimalNum->set(this->getInt64());
722 break;
723 default:
724 // The formattable's value is not a numeric type.
725 status = U_INVALID_STATE_ERROR;
726 return "";
727 }
728 }
729
730 fDecimalStr = new CharString;
731 if (fDecimalStr == NULL) {
732 status = U_MEMORY_ALLOCATION_ERROR;
733 return "";
734 }
735 fDecimalNum->getDecimal(*fDecimalStr, status);
736
737 return fDecimalStr->toStringPiece();
738 }
739
740
741 DigitList *
742 Formattable::getInternalDigitList() {
743 FmtStackData *stackData = (FmtStackData*)fStackData;
744 if(fDecimalNum != &(stackData->stackDecimalNum)) {
745 delete fDecimalNum;
746 fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList();
747 } else {
748 fDecimalNum->clear();
749 }
750 return fDecimalNum;
751 }
752
753 // ---------------------------------------
754 void
755 Formattable::adoptDigitList(DigitList *dl) {
756 if(fDecimalNum==dl) {
757 fDecimalNum = NULL; // don't delete
758 }
759 dispose();
760
761 fDecimalNum = dl;
762
763 if(dl==NULL) { // allow adoptDigitList(NULL) to clear
764 return;
765 }
766
767 // Set the value into the Union of simple type values.
768 // Cannot use the set() functions because they would delete the fDecimalNum value,
769
770 if (fDecimalNum->fitsIntoLong(FALSE)) {
771 fType = kLong;
772 fValue.fInt64 = fDecimalNum->getLong();
773 } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
774 fType = kInt64;
775 fValue.fInt64 = fDecimalNum->getInt64();
776 } else {
777 fType = kDouble;
778 fValue.fDouble = fDecimalNum->getDouble();
779 }
780 }
781
782
783 // ---------------------------------------
784 void
785 Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
786 if (U_FAILURE(status)) {
787 return;
788 }
789 dispose();
790
791 // Copy the input string and nul-terminate it.
792 // The decNumber library requires nul-terminated input. StringPiece input
793 // is not guaranteed nul-terminated. Too bad.
794 // CharString automatically adds the nul.
795 DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList
796 if (dnum == NULL) {
797 status = U_MEMORY_ALLOCATION_ERROR;
798 return;
799 }
800 dnum->set(CharString(numberString, status).toStringPiece(), status);
801 if (U_FAILURE(status)) {
802 delete dnum;
803 return; // String didn't contain a decimal number.
804 }
805 adoptDigitList(dnum);
806
807 // Note that we do not hang on to the caller's input string.
808 // If we are asked for the string, we will regenerate one from fDecimalNum.
809 }
810
811 #if 0
812 //----------------------------------------------------
813 // console I/O
814 //----------------------------------------------------
815 #ifdef _DEBUG
816
817 #include <iostream>
818 using namespace std;
819
820 #include "unicode/datefmt.h"
821 #include "unistrm.h"
822
823 class FormattableStreamer /* not : public UObject because all methods are static */ {
824 public:
825 static void streamOut(ostream& stream, const Formattable& obj);
826
827 private:
828 FormattableStreamer() {} // private - forbid instantiation
829 };
830
831 // This is for debugging purposes only. This will send a displayable
832 // form of the Formattable object to the output stream.
833
834 void
835 FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
836 {
837 static DateFormat *defDateFormat = 0;
838
839 UnicodeString buffer;
840 switch(obj.getType()) {
841 case Formattable::kDate :
842 // Creates a DateFormat instance for formatting the
843 // Date instance.
844 if (defDateFormat == 0) {
845 defDateFormat = DateFormat::createInstance();
846 }
847 defDateFormat->format(obj.getDate(), buffer);
848 stream << buffer;
849 break;
850 case Formattable::kDouble :
851 // Output the double as is.
852 stream << obj.getDouble() << 'D';
853 break;
854 case Formattable::kLong :
855 // Output the double as is.
856 stream << obj.getLong() << 'L';
857 break;
858 case Formattable::kString:
859 // Output the double as is. Please see UnicodeString console
860 // I/O routine for more details.
861 stream << '"' << obj.getString(buffer) << '"';
862 break;
863 case Formattable::kArray:
864 int32_t i, count;
865 const Formattable* array;
866 array = obj.getArray(count);
867 stream << '[';
868 // Recursively calling the console I/O routine for each element in the array.
869 for (i=0; i<count; ++i) {
870 FormattableStreamer::streamOut(stream, array[i]);
871 stream << ( (i==(count-1)) ? "" : ", " );
872 }
873 stream << ']';
874 break;
875 default:
876 // Not a recognizable Formattable object.
877 stream << "INVALID_Formattable";
878 }
879 stream.flush();
880 }
881 #endif
882
883 #endif
884
885 U_NAMESPACE_END
886
887 #endif /* #if !UCONFIG_NO_FORMATTING */
888
889 //eof