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 890