intl/icu/source/i18n/fmtable.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial