1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2006, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 *
7 * File FMTABLE.CPP
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 * 03/25/97 clhuang Initial Implementation.
13 ********************************************************************************
14 */
15
16 #include "unicode/utypes.h"
17
18 #if !UCONFIG_NO_FORMATTING
19
20 #include "unicode/fmtable.h"
21 #include "unicode/ustring.h"
22 #include "unicode/measure.h"
23 #include "unicode/curramt.h"
24 #include "cmemory.h"
25
26 // *****************************************************************************
27 // class Formattable
28 // *****************************************************************************
29
30 U_NAMESPACE_BEGIN
31
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)32 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
33
34 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
35
36 // NOTE: As of 3.0, there are limitations to the UObject API. It does
37 // not (yet) support cloning, operator=, nor operator==. RTTI is also
38 // restricted in that subtype testing is not (yet) implemented. To
39 // work around this, I implement some simple inlines here. Later
40 // these can be modified or removed. [alan]
41
42 // NOTE: These inlines assume that all fObjects are in fact instances
43 // of the Measure class, which is true as of 3.0. [alan]
44
45 // Return TRUE if *a == *b.
46 static inline UBool objectEquals(const UObject* a, const UObject* b) {
47 // LATER: return *a == *b;
48 return *((const Measure*) a) == *((const Measure*) b);
49 }
50
51 // Return a clone of *a.
objectClone(const UObject * a)52 static inline UObject* objectClone(const UObject* a) {
53 // LATER: return a->clone();
54 return ((const Measure*) a)->clone();
55 }
56
57 // Return TRUE if *a is an instance of Measure.
instanceOfMeasure(const UObject * a)58 static inline UBool instanceOfMeasure(const UObject* a) {
59 // LATER: return a->instanceof(Measure::getStaticClassID());
60 return a->getDynamicClassID() ==
61 CurrencyAmount::getStaticClassID();
62 }
63
64 /**
65 * Creates a new Formattable array and copies the values from the specified
66 * original.
67 * @param array the original array
68 * @param count the original array count
69 * @return the new Formattable array.
70 */
createArrayCopy(const Formattable * array,int32_t count)71 static inline Formattable* createArrayCopy(const Formattable* array, int32_t count) {
72 Formattable *result = new Formattable[count];
73 for (int32_t i=0; i<count; ++i) result[i] = array[i]; // Don't memcpy!
74 return result;
75 }
76
77 //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
78
79 /**
80 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
81 */
setError(UErrorCode & ec,UErrorCode err)82 static inline void setError(UErrorCode& ec, UErrorCode err) {
83 if (U_SUCCESS(ec)) {
84 ec = err;
85 }
86 }
87
88 // -------------------------------------
89 // default constructor.
90 // Creates a formattable object with a long value 0.
91
Formattable()92 Formattable::Formattable()
93 : UObject(), fType(kLong)
94 {
95 fBogus.setToBogus();
96 fValue.fInt64 = 0;
97 }
98
99 // -------------------------------------
100 // Creates a formattable object with a Date instance.
101
Formattable(UDate date,ISDATE)102 Formattable::Formattable(UDate date, ISDATE /*isDate*/)
103 : UObject(), fType(kDate)
104 {
105 fBogus.setToBogus();
106 fValue.fDate = date;
107 }
108
109 // -------------------------------------
110 // Creates a formattable object with a double value.
111
Formattable(double value)112 Formattable::Formattable(double value)
113 : UObject(), fType(kDouble)
114 {
115 fBogus.setToBogus();
116 fValue.fDouble = value;
117 }
118
119 // -------------------------------------
120 // Creates a formattable object with a long value.
121
Formattable(int32_t value)122 Formattable::Formattable(int32_t value)
123 : UObject(), fType(kLong)
124 {
125 fBogus.setToBogus();
126 fValue.fInt64 = value;
127 }
128
129 // -------------------------------------
130 // Creates a formattable object with a long value.
131
Formattable(int64_t value)132 Formattable::Formattable(int64_t value)
133 : UObject(), fType(kInt64)
134 {
135 fBogus.setToBogus();
136 fValue.fInt64 = value;
137 }
138
139 // -------------------------------------
140 // Creates a formattable object with a UnicodeString instance.
141
Formattable(const UnicodeString & stringToCopy)142 Formattable::Formattable(const UnicodeString& stringToCopy)
143 : UObject(), fType(kString)
144 {
145 fBogus.setToBogus();
146 fValue.fString = new UnicodeString(stringToCopy);
147 }
148
149 // -------------------------------------
150 // Creates a formattable object with a UnicodeString* value.
151 // (adopting symantics)
152
Formattable(UnicodeString * stringToAdopt)153 Formattable::Formattable(UnicodeString* stringToAdopt)
154 : UObject(), fType(kString)
155 {
156 fBogus.setToBogus();
157 fValue.fString = stringToAdopt;
158 }
159
Formattable(UObject * objectToAdopt)160 Formattable::Formattable(UObject* objectToAdopt)
161 : UObject(), fType(kObject)
162 {
163 fBogus.setToBogus();
164 fValue.fObject = objectToAdopt;
165 }
166
167 // -------------------------------------
168
Formattable(const Formattable * arrayToCopy,int32_t count)169 Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
170 : UObject(), fType(kArray)
171 {
172 fBogus.setToBogus();
173 fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
174 fValue.fArrayAndCount.fCount = count;
175 }
176
177 // -------------------------------------
178 // copy constructor
179
Formattable(const Formattable & source)180 Formattable::Formattable(const Formattable &source)
181 : UObject(source), fType(kLong)
182 {
183 fBogus.setToBogus();
184 *this = source;
185 }
186
187 // -------------------------------------
188 // assignment operator
189
190 Formattable&
operator =(const Formattable & source)191 Formattable::operator=(const Formattable& source)
192 {
193 if (this != &source)
194 {
195 // Disposes the current formattable value/setting.
196 dispose();
197
198 // Sets the correct data type for this value.
199 fType = source.fType;
200 switch (fType)
201 {
202 case kArray:
203 // Sets each element in the array one by one and records the array count.
204 fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
205 fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
206 source.fValue.fArrayAndCount.fCount);
207 break;
208 case kString:
209 // Sets the string value.
210 fValue.fString = new UnicodeString(*source.fValue.fString);
211 break;
212 case kDouble:
213 // Sets the double value.
214 fValue.fDouble = source.fValue.fDouble;
215 break;
216 case kLong:
217 case kInt64:
218 // Sets the long value.
219 fValue.fInt64 = source.fValue.fInt64;
220 break;
221 case kDate:
222 // Sets the Date value.
223 fValue.fDate = source.fValue.fDate;
224 break;
225 case kObject:
226 fValue.fObject = objectClone(source.fValue.fObject);
227 break;
228 }
229 }
230 return *this;
231 }
232
233 // -------------------------------------
234
235 UBool
operator ==(const Formattable & that) const236 Formattable::operator==(const Formattable& that) const
237 {
238 int32_t i;
239
240 if (this == &that) return TRUE;
241
242 // Returns FALSE if the data types are different.
243 if (fType != that.fType) return FALSE;
244
245 // Compares the actual data values.
246 UBool equal = TRUE;
247 switch (fType) {
248 case kDate:
249 equal = (fValue.fDate == that.fValue.fDate);
250 break;
251 case kDouble:
252 equal = (fValue.fDouble == that.fValue.fDouble);
253 break;
254 case kLong:
255 case kInt64:
256 equal = (fValue.fInt64 == that.fValue.fInt64);
257 break;
258 case kString:
259 equal = (*(fValue.fString) == *(that.fValue.fString));
260 break;
261 case kArray:
262 if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
263 equal = FALSE;
264 break;
265 }
266 // Checks each element for equality.
267 for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
268 if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
269 equal = FALSE;
270 break;
271 }
272 }
273 break;
274 case kObject:
275 equal = objectEquals(fValue.fObject, that.fValue.fObject);
276 break;
277 }
278
279 return equal;
280 }
281
282 // -------------------------------------
283
~Formattable()284 Formattable::~Formattable()
285 {
286 dispose();
287 }
288
289 // -------------------------------------
290
dispose()291 void Formattable::dispose()
292 {
293 // Deletes the data value if necessary.
294 switch (fType) {
295 case kString:
296 delete fValue.fString;
297 break;
298 case kArray:
299 delete[] fValue.fArrayAndCount.fArray;
300 break;
301 case kObject:
302 delete fValue.fObject;
303 break;
304 default:
305 break;
306 }
307 }
308
309 Formattable *
clone() const310 Formattable::clone() const {
311 return new Formattable(*this);
312 }
313
314 // -------------------------------------
315 // Gets the data type of this Formattable object.
316 Formattable::Type
getType() const317 Formattable::getType() const
318 {
319 return fType;
320 }
321
322 UBool
isNumeric() const323 Formattable::isNumeric() const {
324 switch (fType) {
325 case kDouble:
326 case kLong:
327 case kInt64:
328 return TRUE;
329 default:
330 return FALSE;
331 }
332 }
333
334 // -------------------------------------
335 int32_t
336 //Formattable::getLong(UErrorCode* status) const
getLong(UErrorCode & status) const337 Formattable::getLong(UErrorCode& status) const
338 {
339 if (U_FAILURE(status)) {
340 return 0;
341 }
342
343 switch (fType) {
344 case Formattable::kLong:
345 return (int32_t)fValue.fInt64;
346 case Formattable::kInt64:
347 if (fValue.fInt64 > INT32_MAX) {
348 status = U_INVALID_FORMAT_ERROR;
349 return INT32_MAX;
350 } else if (fValue.fInt64 < INT32_MIN) {
351 status = U_INVALID_FORMAT_ERROR;
352 return INT32_MIN;
353 } else {
354 return (int32_t)fValue.fInt64;
355 }
356 case Formattable::kDouble:
357 if (fValue.fDouble > INT32_MAX) {
358 status = U_INVALID_FORMAT_ERROR;
359 return INT32_MAX;
360 } else if (fValue.fDouble < INT32_MIN) {
361 status = U_INVALID_FORMAT_ERROR;
362 return INT32_MIN;
363 } else {
364 return (int32_t)fValue.fDouble; // loses fraction
365 }
366 case Formattable::kObject:
367 // TODO Later replace this with instanceof call
368 if (instanceOfMeasure(fValue.fObject)) {
369 return ((const Measure*) fValue.fObject)->
370 getNumber().getLong(status);
371 }
372 default:
373 status = U_INVALID_FORMAT_ERROR;
374 return 0;
375 }
376 }
377
378 // -------------------------------------
379 int64_t
getInt64(UErrorCode & status) const380 Formattable::getInt64(UErrorCode& status) const
381 {
382 if (U_FAILURE(status)) {
383 return 0;
384 }
385
386 switch (fType) {
387 case Formattable::kLong:
388 case Formattable::kInt64:
389 return fValue.fInt64;
390 case Formattable::kDouble:
391 if (fValue.fDouble > U_INT64_MAX) {
392 status = U_INVALID_FORMAT_ERROR;
393 return U_INT64_MAX;
394 } else if (fValue.fDouble < U_INT64_MIN) {
395 status = U_INVALID_FORMAT_ERROR;
396 return U_INT64_MIN;
397 } else {
398 return (int64_t)fValue.fDouble;
399 }
400 case Formattable::kObject:
401 // TODO Later replace this with instanceof call
402 if (instanceOfMeasure(fValue.fObject)) {
403 return ((const Measure*) fValue.fObject)->
404 getNumber().getInt64(status);
405 }
406 default:
407 status = U_INVALID_FORMAT_ERROR;
408 return 0;
409 }
410 }
411
412 // -------------------------------------
413 double
getDouble(UErrorCode & status) const414 Formattable::getDouble(UErrorCode& status) const
415 {
416 if (U_FAILURE(status)) {
417 return 0;
418 }
419
420 switch (fType) {
421 case Formattable::kLong:
422 case Formattable::kInt64: // loses precision
423 return (double)fValue.fInt64;
424 case Formattable::kDouble:
425 return fValue.fDouble;
426 case Formattable::kObject:
427 // TODO Later replace this with instanceof call
428 if (instanceOfMeasure(fValue.fObject)) {
429 return ((const Measure*) fValue.fObject)->
430 getNumber().getDouble(status);
431 }
432 default:
433 status = U_INVALID_FORMAT_ERROR;
434 return 0;
435 }
436 }
437
438 const UObject*
getObject() const439 Formattable::getObject() const {
440 return (fType == kObject) ? fValue.fObject : NULL;
441 }
442
443 // -------------------------------------
444 // Sets the value to a double value d.
445
446 void
setDouble(double d)447 Formattable::setDouble(double d)
448 {
449 dispose();
450 fType = kDouble;
451 fValue.fDouble = d;
452 }
453
454 // -------------------------------------
455 // Sets the value to a long value l.
456
457 void
setLong(int32_t l)458 Formattable::setLong(int32_t l)
459 {
460 dispose();
461 fType = kLong;
462 fValue.fInt64 = l;
463 }
464
465 // -------------------------------------
466 // Sets the value to an int64 value ll.
467
468 void
setInt64(int64_t ll)469 Formattable::setInt64(int64_t ll)
470 {
471 dispose();
472 fType = kInt64;
473 fValue.fInt64 = ll;
474 }
475
476 // -------------------------------------
477 // Sets the value to a Date instance d.
478
479 void
setDate(UDate d)480 Formattable::setDate(UDate d)
481 {
482 dispose();
483 fType = kDate;
484 fValue.fDate = d;
485 }
486
487 // -------------------------------------
488 // Sets the value to a string value stringToCopy.
489
490 void
setString(const UnicodeString & stringToCopy)491 Formattable::setString(const UnicodeString& stringToCopy)
492 {
493 dispose();
494 fType = kString;
495 fValue.fString = new UnicodeString(stringToCopy);
496 }
497
498 // -------------------------------------
499 // Sets the value to an array of Formattable objects.
500
501 void
setArray(const Formattable * array,int32_t count)502 Formattable::setArray(const Formattable* array, int32_t count)
503 {
504 dispose();
505 fType = kArray;
506 fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
507 fValue.fArrayAndCount.fCount = count;
508 }
509
510 // -------------------------------------
511 // Adopts the stringToAdopt value.
512
513 void
adoptString(UnicodeString * stringToAdopt)514 Formattable::adoptString(UnicodeString* stringToAdopt)
515 {
516 dispose();
517 fType = kString;
518 fValue.fString = stringToAdopt;
519 }
520
521 // -------------------------------------
522 // Adopts the array value and its count.
523
524 void
adoptArray(Formattable * array,int32_t count)525 Formattable::adoptArray(Formattable* array, int32_t count)
526 {
527 dispose();
528 fType = kArray;
529 fValue.fArrayAndCount.fArray = array;
530 fValue.fArrayAndCount.fCount = count;
531 }
532
533 void
adoptObject(UObject * objectToAdopt)534 Formattable::adoptObject(UObject* objectToAdopt) {
535 dispose();
536 fType = kObject;
537 fValue.fObject = objectToAdopt;
538 }
539
540 // -------------------------------------
541 UnicodeString&
getString(UnicodeString & result,UErrorCode & status) const542 Formattable::getString(UnicodeString& result, UErrorCode& status) const
543 {
544 if (fType != kString) {
545 setError(status, U_INVALID_FORMAT_ERROR);
546 result.setToBogus();
547 } else {
548 result = *fValue.fString;
549 }
550 return result;
551 }
552
553 // -------------------------------------
554 const UnicodeString&
getString(UErrorCode & status) const555 Formattable::getString(UErrorCode& status) const
556 {
557 if (fType != kString) {
558 setError(status, U_INVALID_FORMAT_ERROR);
559 return *getBogus();
560 }
561 return *fValue.fString;
562 }
563
564 // -------------------------------------
565 UnicodeString&
getString(UErrorCode & status)566 Formattable::getString(UErrorCode& status)
567 {
568 if (fType != kString) {
569 setError(status, U_INVALID_FORMAT_ERROR);
570 return *getBogus();
571 }
572 return *fValue.fString;
573 }
574
575 // -------------------------------------
576 const Formattable*
getArray(int32_t & count,UErrorCode & status) const577 Formattable::getArray(int32_t& count, UErrorCode& status) const
578 {
579 if (fType != kArray) {
580 setError(status, U_INVALID_FORMAT_ERROR);
581 count = 0;
582 return NULL;
583 }
584 count = fValue.fArrayAndCount.fCount;
585 return fValue.fArrayAndCount.fArray;
586 }
587
588 // -------------------------------------
589 // Gets the bogus string, ensures mondo bogosity.
590
591 UnicodeString*
getBogus() const592 Formattable::getBogus() const
593 {
594 return (UnicodeString*)&fBogus; /* cast away const :-( */
595 }
596
597 #if 0
598 //----------------------------------------------------
599 // console I/O
600 //----------------------------------------------------
601 #ifdef _DEBUG
602
603 #if U_IOSTREAM_SOURCE >= 199711
604 #include <iostream>
605 using namespace std;
606 #elif U_IOSTREAM_SOURCE >= 198506
607 #include <iostream.h>
608 #endif
609
610 #include "unicode/datefmt.h"
611 #include "unistrm.h"
612
613 class FormattableStreamer /* not : public UObject because all methods are static */ {
614 public:
615 static void streamOut(ostream& stream, const Formattable& obj);
616
617 private:
618 FormattableStreamer() {} // private - forbid instantiation
619 };
620
621 // This is for debugging purposes only. This will send a displayable
622 // form of the Formattable object to the output stream.
623
624 void
625 FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
626 {
627 static DateFormat *defDateFormat = 0;
628
629 UnicodeString buffer;
630 switch(obj.getType()) {
631 case Formattable::kDate :
632 // Creates a DateFormat instance for formatting the
633 // Date instance.
634 if (defDateFormat == 0) {
635 defDateFormat = DateFormat::createInstance();
636 }
637 defDateFormat->format(obj.getDate(), buffer);
638 stream << buffer;
639 break;
640 case Formattable::kDouble :
641 // Output the double as is.
642 stream << obj.getDouble() << 'D';
643 break;
644 case Formattable::kLong :
645 // Output the double as is.
646 stream << obj.getLong() << 'L';
647 break;
648 case Formattable::kString:
649 // Output the double as is. Please see UnicodeString console
650 // I/O routine for more details.
651 stream << '"' << obj.getString(buffer) << '"';
652 break;
653 case Formattable::kArray:
654 int32_t i, count;
655 const Formattable* array;
656 array = obj.getArray(count);
657 stream << '[';
658 // Recursively calling the console I/O routine for each element in the array.
659 for (i=0; i<count; ++i) {
660 FormattableStreamer::streamOut(stream, array[i]);
661 stream << ( (i==(count-1)) ? "" : ", " );
662 }
663 stream << ']';
664 break;
665 default:
666 // Not a recognizable Formattable object.
667 stream << "INVALID_Formattable";
668 }
669 stream.flush();
670 }
671 #endif
672
673 #endif
674
675 U_NAMESPACE_END
676
677 #endif /* #if !UCONFIG_NO_FORMATTING */
678
679 //eof
680