// NOTE: As of 3.0, there are limitations to the UObject API. It does // not (yet) support cloning, operator=, nor operator==. To // work around this, I implement some simple inlines here. Later // these can be modified or removed. [alan]
// NOTE: These inlines assume that all fObjects are in fact instances // of the Measure class, which is true as of 3.0. [alan]
// Return true if *a == *b. staticinline UBool objectEquals(const UObject* a, const UObject* b) { // LATER: return *a == *b; return *((const Measure*) a) == *b;
}
// Return a clone of *a. staticinline UObject* objectClone(const UObject* a) { // LATER: return a->clone(); return ((const Measure*) a)->clone();
}
// Return true if *a is an instance of Measure. staticinline UBool instanceOfMeasure(const UObject* a) { returndynamic_cast<const Measure*>(a) != nullptr;
}
/** * Creates a new Formattable array and copies the values from the specified * original. * @param array the original array * @param count the original array count * @return the new Formattable array.
*/ static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
Formattable *result = new Formattable[count]; if (result != nullptr) { for (int32_t i=0; i<count; ++i)
result[i] = array[i]; // Don't memcpy!
} return result;
}
/** * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
*/ staticvoid setError(UErrorCode& ec, UErrorCode err) { if (U_SUCCESS(ec)) {
ec = err;
}
}
// // Common initialization code, shared by constructors. // Put everything into a known state. // void Formattable::init() {
fValue.fInt64 = 0;
fType = kLong;
fDecimalStr = nullptr;
fDecimalQuantity = nullptr;
fBogus.setToBogus();
}
// ------------------------------------- // default constructor. // Creates a formattable object with a long value 0.
Formattable::Formattable() {
init();
}
// ------------------------------------- // Creates a formattable object with a Date instance.
Formattable&
Formattable::operator=(const Formattable& source)
{ if (this != &source)
{ // Disposes the current formattable value/setting.
dispose();
// Sets the correct data type for this value.
fType = source.fType; switch (fType)
{ case kArray: // Sets each element in the array one by one and records the array count.
fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
source.fValue.fArrayAndCount.fCount); break; case kString: // Sets the string value.
fValue.fString = new UnicodeString(*source.fValue.fString); break; case kDouble: // Sets the double value.
fValue.fDouble = source.fValue.fDouble; break; case kLong: case kInt64: // Sets the long value.
fValue.fInt64 = source.fValue.fInt64; break; case kDate: // Sets the Date value.
fValue.fDate = source.fValue.fDate; break; case kObject:
fValue.fObject = objectClone(source.fValue.fObject); break;
}
UErrorCode status = U_ZERO_ERROR; if (source.fDecimalQuantity != nullptr) {
fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity);
} if (source.fDecimalStr != nullptr) {
fDecimalStr = new CharString(*source.fDecimalStr, status); if (U_FAILURE(status)) { delete fDecimalStr;
fDecimalStr = nullptr;
}
}
} return *this;
}
// Returns false if the data types are different. if (fType != that.fType) returnfalse;
// Compares the actual data values. bool equal = true; switch (fType) { case kDate:
equal = (fValue.fDate == that.fValue.fDate); break; case kDouble:
equal = (fValue.fDouble == that.fValue.fDouble); break; case kLong: case kInt64:
equal = (fValue.fInt64 == that.fValue.fInt64); break; case kString:
equal = (*(fValue.fString) == *(that.fValue.fString)); break; case kArray: if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
equal = false; break;
} // Checks each element for equality. for (i=0; i<fValue.fArrayAndCount.fCount; ++i) { if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
equal = false; break;
}
} break; case kObject: if (fValue.fObject == nullptr || that.fValue.fObject == nullptr) {
equal = false;
} else {
equal = objectEquals(fValue.fObject, that.fValue.fObject);
} break;
}
// TODO: compare digit lists if numeric. return equal;
}
// -------------------------------------
Formattable::~Formattable()
{
dispose();
}
// -------------------------------------
void Formattable::dispose()
{ // Deletes the data value if necessary. switch (fType) { case kString: delete fValue.fString; break; case kArray: delete[] fValue.fArrayAndCount.fArray; break; case kObject: delete fValue.fObject; break; default: break;
}
// ------------------------------------- // Gets the data type of this Formattable object.
Formattable::Type
Formattable::getType() const
{ return fType;
}
UBool
Formattable::isNumeric() const { switch (fType) { case kDouble: case kLong: case kInt64: returntrue; default: returnfalse;
}
}
switch (fType) { case Formattable::kLong: returnstatic_cast<int32_t>(fValue.fInt64); case Formattable::kInt64: if (fValue.fInt64 > INT32_MAX) {
status = U_INVALID_FORMAT_ERROR; return INT32_MAX;
} elseif (fValue.fInt64 < INT32_MIN) {
status = U_INVALID_FORMAT_ERROR; return INT32_MIN;
} else { returnstatic_cast<int32_t>(fValue.fInt64);
} case Formattable::kDouble: if (fValue.fDouble > INT32_MAX) {
status = U_INVALID_FORMAT_ERROR; return INT32_MAX;
} elseif (fValue.fDouble < INT32_MIN) {
status = U_INVALID_FORMAT_ERROR; return INT32_MIN;
} else { returnstatic_cast<int32_t>(fValue.fDouble); // loses fraction
} case Formattable::kObject: if (fValue.fObject == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return 0;
} // TODO Later replace this with instanceof call if (instanceOfMeasure(fValue.fObject)) { return ((const Measure*) fValue.fObject)->
getNumber().getLong(status);
}
U_FALLTHROUGH; default:
status = U_INVALID_FORMAT_ERROR; return 0;
}
}
// ------------------------------------- // Maximum int that can be represented exactly in a double. (53 bits) // Larger ints may be rounded to a near-by value as not all are representable. // TODO: move this constant elsewhere, possibly configure it for different // floating point formats, if any non-standard ones are still in use. staticconst int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL;
switch (fType) { case Formattable::kLong: case Formattable::kInt64: // loses precision returnstatic_cast<double>(fValue.fInt64); case Formattable::kDouble: return fValue.fDouble; case Formattable::kObject: if (fValue.fObject == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return 0;
} // TODO Later replace this with instanceof call if (instanceOfMeasure(fValue.fObject)) { return ((const Measure*) fValue.fObject)->
getNumber().getDouble(status);
}
U_FALLTHROUGH; default:
status = U_INVALID_FORMAT_ERROR; return 0;
}
}
CharString *Formattable::internalGetCharString(UErrorCode &status) { if(fDecimalStr == nullptr) { if (fDecimalQuantity == nullptr) { // No decimal number for the formattable yet. Which means the value was // set directly by the user as an int, int64 or double. If the value came // from parsing, or from the user setting a decimal number, fDecimalNum // would already be set. //
LocalPointer<DecimalQuantity> dq(new DecimalQuantity(), status); if (U_FAILURE(status)) { return nullptr; }
populateDecimalQuantity(*dq, status); if (U_FAILURE(status)) { return nullptr; }
fDecimalQuantity = dq.orphan();
}
fDecimalStr = new CharString(); if (fDecimalStr == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return nullptr;
} // Older ICUs called uprv_decNumberToString here, which is not exactly the same as // DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?). if (fDecimalQuantity->isInfinite()) {
fDecimalStr->append("Infinity", status);
} elseif (fDecimalQuantity->isNaN()) {
fDecimalStr->append("NaN", status);
} elseif (fDecimalQuantity->isZeroish()) {
fDecimalStr->append("0", -1, status);
} elseif (fType==kLong || fType==kInt64 || // use toPlainString for integer types
(fDecimalQuantity->getMagnitude() != INT32_MIN && std::abs(fDecimalQuantity->getMagnitude()) < 5)) {
fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status);
} else {
fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), status);
}
} return fDecimalStr;
}
switch (fType) { case kDouble:
output.setToDouble(this->getDouble());
output.roundToInfinity(); break; case kLong:
output.setToInt(this->getLong()); break; case kInt64:
output.setToLong(this->getInt64()); break; default: // The formattable's value is not a numeric type.
status = U_INVALID_STATE_ERROR;
}
}
// Set the value into the Union of simple type values. // Cannot use the set() functions because they would delete the fDecimalNum value. if (fDecimalQuantity->fitsInLong()) {
fValue.fInt64 = fDecimalQuantity->toLong(); if (fValue.fInt64 <= INT32_MAX && fValue.fInt64 >= INT32_MIN) {
fType = kLong;
} else {
fType = kInt64;
}
} else {
fType = kDouble;
fValue.fDouble = fDecimalQuantity->toDouble();
}
}
class FormattableStreamer /* not : public UObject because all methods are static */ { public: staticvoid streamOut(ostream& stream, const Formattable& obj);
UnicodeString buffer; switch(obj.getType()) { case Formattable::kDate : // Creates a DateFormat instance for formatting the // Date instance. if (defDateFormat == 0) {
defDateFormat = DateFormat::createInstance();
}
defDateFormat->format(obj.getDate(), buffer);
stream << buffer; break; case Formattable::kDouble : // Output the double as is.
stream << obj.getDouble() << 'D'; break; case Formattable::kLong : // Output the double as is.
stream << obj.getLong() << 'L'; break; case Formattable::kString: // Output the double as is. Please see UnicodeString console // I/O routine for more details.
stream << '"' << obj.getString(buffer) << '"'; break; case Formattable::kArray:
int32_t i, count; const Formattable* array;
array = obj.getArray(count);
stream << '['; // Recursively calling the console I/O routine for each element in the array. for (i=0; i<count; ++i) {
FormattableStreamer::streamOut(stream, array[i]);
stream << ( (i==(count-1)) ? "" : ", " );
}
stream << ']'; break; default: // Not a recognizable Formattable object.
stream << "INVALID_Formattable";
}
stream.flush();
} #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.