double DigitList::getDouble() /*const*/ { double value; if (fCount == 0) { value = 0.0; } else { char* end = NULL; if (!gDecimal) { char rep[MAX_DIGITS]; // For machines that decide to change the decimal on you, // and try to be too smart with localization. // This normally should be just a '.'. sprintf(rep, "%+1.1f", 1.0); gDecimal = rep[2]; } *fDecimalDigits = gDecimal; *(fDigits+fCount) = 'e'; // add an e after the digits. formatBase10(fDecimalAt, fDigits + fCount + 1, // skip the 'e' MAX_DEC_DIGITS - fCount - 3); // skip the 'e' and '.' value = uprv_strtod(fDecimalDigits, &end); } return fIsPositive ? value : -value; }
/** * Currently, getDouble() depends on atof() to do its conversion. * * WARNING!! * This is an extremely costly function. ~1/2 of the conversion time * can be linked to this function. */ double DigitList::getDouble() const { // TODO: fix thread safety. Can probably be finessed some by analyzing // what public const functions can see which DigitLists. // Like precompute fDouble for DigitLists coming in from a parse // or from a Formattable::set(), but not for any others. if (fHaveDouble) { return fDouble; } DigitList *nonConstThis = const_cast<DigitList *>(this); if (isZero()) { nonConstThis->fDouble = 0.0; if (decNumberIsNegative(fDecNumber)) { nonConstThis->fDouble /= -1; } } else if (isInfinite()) { if (std::numeric_limits<double>::has_infinity) { nonConstThis->fDouble = std::numeric_limits<double>::infinity(); } else { nonConstThis->fDouble = std::numeric_limits<double>::max(); } if (!isPositive()) { nonConstThis->fDouble = -fDouble; } } else { MaybeStackArray<char, MAX_DBL_DIGITS+18> s; // Note: 14 is a magic constant from the decNumber library documentation, // the max number of extra characters beyond the number of digits // needed to represent the number in string form. Add a few more // for the additional digits we retain. // Round down to appx. double precision, if the number is longer than that. // Copy the number first, so that we don't modify the original. if (getCount() > MAX_DBL_DIGITS + 3) { DigitList numToConvert(*this); numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. numToConvert.round(MAX_DBL_DIGITS+3); uprv_decNumberToString(numToConvert.fDecNumber, s); // TODO: how many extra digits should be included for an accurate conversion? } else { uprv_decNumberToString(this->fDecNumber, s); } U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); loadDecimalChar(); if (gDecimal != '.') { char *decimalPt = strchr(s, '.'); if (decimalPt != NULL) { *decimalPt = gDecimal; } } char *end = NULL; nonConstThis->fDouble = uprv_strtod(s, &end); } nonConstThis->fHaveDouble = TRUE; return fDouble; }
/** * Convert a string to a double value */ double ChoiceFormat::stod(const UnicodeString& string) { char source[256]; char* end; string.extract(0, string.length(), source, sizeof(source), ""); /* invariant codepage */ return uprv_strtod(source,&end); }
U_CDECL_END double DigitList::decimalStrToDouble(char *decstr, char **end) { umtx_initOnce(gCLocaleInitOnce, &initCLocale); #if U_USE_STRTOD_L return strtod_l(decstr, end, gCLocale); #else char *decimalPt = strchr(decstr, '.'); if (decimalPt) { // We need to know the decimal separator character that will be used with strtod(). // Depends on the C runtime global locale. // Most commonly is '.' char rep[MAX_DIGITS]; sprintf(rep, "%+1.1f", 1.0); *decimalPt = rep[2]; } return uprv_strtod(decstr, end); #endif }
UnicodeSet& UnicodeSet::applyPropertyAlias(const UnicodeString& prop, const UnicodeString& value, UErrorCode& ec) { if (U_FAILURE(ec) || isFrozen()) return *this; // prop and value used to be converted to char * using the default // converter instead of the invariant conversion. // This should not be necessary because all Unicode property and value // names use only invariant characters. // If there are any variant characters, then we won't find them anyway. // Checking first avoids assertion failures in the conversion. if( !uprv_isInvariantUString(prop.getBuffer(), prop.length()) || !uprv_isInvariantUString(value.getBuffer(), value.length()) ) { FAIL(ec); } CharString pname, vname; pname.appendInvariantChars(prop, ec); vname.appendInvariantChars(value, ec); if (U_FAILURE(ec)) return *this; UProperty p; int32_t v; UBool mustNotBeEmpty = FALSE, invert = FALSE; if (value.length() > 0) { p = u_getPropertyEnum(pname.data()); if (p == UCHAR_INVALID_CODE) FAIL(ec); // Treat gc as gcm if (p == UCHAR_GENERAL_CATEGORY) { p = UCHAR_GENERAL_CATEGORY_MASK; } if ((p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) || (p >= UCHAR_INT_START && p < UCHAR_INT_LIMIT) || (p >= UCHAR_MASK_START && p < UCHAR_MASK_LIMIT)) { v = u_getPropertyValueEnum(p, vname.data()); if (v == UCHAR_INVALID_CODE) { // Handle numeric CCC if (p == UCHAR_CANONICAL_COMBINING_CLASS || p == UCHAR_TRAIL_CANONICAL_COMBINING_CLASS || p == UCHAR_LEAD_CANONICAL_COMBINING_CLASS) { char* end; double value = uprv_strtod(vname.data(), &end); v = (int32_t) value; if (v != value || v < 0 || *end != 0) { // non-integral or negative value, or trailing junk FAIL(ec); } // If the resultant set is empty then the numeric value // was invalid. mustNotBeEmpty = TRUE; } else { FAIL(ec); } } } else { switch (p) { case UCHAR_NUMERIC_VALUE: { char* end; double value = uprv_strtod(vname.data(), &end); if (*end != 0) { FAIL(ec); } applyFilter(numericValueFilter, &value, UPROPS_SRC_CHAR, ec); return *this; } case UCHAR_NAME: { // Must munge name, since u_charFromName() does not do // 'loose' matching. char buf[128]; // it suffices that this be > uprv_getMaxCharNameLength if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec); UChar32 ch = u_charFromName(U_EXTENDED_CHAR_NAME, buf, &ec); if (U_SUCCESS(ec)) { clear(); add(ch); return *this; } else { FAIL(ec); } } case UCHAR_UNICODE_1_NAME: // ICU 49 deprecates the Unicode_1_Name property APIs. FAIL(ec); case UCHAR_AGE: { // Must munge name, since u_versionFromString() does not do // 'loose' matching. char buf[128]; if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec); UVersionInfo version; u_versionFromString(version, buf); applyFilter(versionFilter, &version, UPROPS_SRC_PROPSVEC, ec); return *this; } case UCHAR_SCRIPT_EXTENSIONS: v = u_getPropertyValueEnum(UCHAR_SCRIPT, vname.data()); if (v == UCHAR_INVALID_CODE) { FAIL(ec); } // fall through to calling applyIntPropertyValue() break; default: // p is a non-binary, non-enumerated property that we // don't support (yet). FAIL(ec); } } } else { // value is empty. Interpret as General Category, Script, or // Binary property. p = UCHAR_GENERAL_CATEGORY_MASK; v = u_getPropertyValueEnum(p, pname.data()); if (v == UCHAR_INVALID_CODE) { p = UCHAR_SCRIPT; v = u_getPropertyValueEnum(p, pname.data()); if (v == UCHAR_INVALID_CODE) { p = u_getPropertyEnum(pname.data()); if (p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) { v = 1; } else if (0 == uprv_comparePropertyNames(ANY, pname.data())) { set(MIN_VALUE, MAX_VALUE); return *this; } else if (0 == uprv_comparePropertyNames(ASCII, pname.data())) { set(0, 0x7F); return *this; } else if (0 == uprv_comparePropertyNames(ASSIGNED, pname.data())) { // [:Assigned:]=[:^Cn:] p = UCHAR_GENERAL_CATEGORY_MASK; v = U_GC_CN_MASK; invert = TRUE; } else { FAIL(ec); } } } } applyIntPropertyValue(p, v, ec); if(invert) { complement(); } if (U_SUCCESS(ec) && (mustNotBeEmpty && isEmpty())) { // mustNotBeEmpty is set to true if an empty set indicates // invalid input. ec = U_ILLEGAL_ARGUMENT_ERROR; } if (isBogus() && U_SUCCESS(ec)) { // We likely ran out of memory. AHHH! ec = U_MEMORY_ALLOCATION_ERROR; } return *this; }
/** * Currently, getDouble() depends on strtod() to do its conversion. * * WARNING!! * This is an extremely costly function. ~1/2 of the conversion time * can be linked to this function. */ double DigitList::getDouble() const { static char gDecimal = 0; char decimalSeparator; { Mutex mutex; if (fHave == kDouble) { return fUnion.fDouble; } else if(fHave == kInt64) { return (double)fUnion.fInt64; } decimalSeparator = gDecimal; } if (decimalSeparator == 0) { // We need to know the decimal separator character that will be used with strtod(). // Depends on the C runtime global locale. // Most commonly is '.' // TODO: caching could fail if the global locale is changed on the fly. char rep[MAX_DIGITS]; sprintf(rep, "%+1.1f", 1.0); decimalSeparator = rep[2]; } double tDouble = 0.0; if (isZero()) { tDouble = 0.0; if (decNumberIsNegative(fDecNumber)) { tDouble /= -1; } } else if (isInfinite()) { if (std::numeric_limits<double>::has_infinity) { tDouble = std::numeric_limits<double>::infinity(); } else { tDouble = std::numeric_limits<double>::max(); } if (!isPositive()) { tDouble = -tDouble; //this was incorrectly "-fDouble" originally. } } else { MaybeStackArray<char, MAX_DBL_DIGITS+18> s; // Note: 14 is a magic constant from the decNumber library documentation, // the max number of extra characters beyond the number of digits // needed to represent the number in string form. Add a few more // for the additional digits we retain. // Round down to appx. double precision, if the number is longer than that. // Copy the number first, so that we don't modify the original. if (getCount() > MAX_DBL_DIGITS + 3) { DigitList numToConvert(*this); numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. numToConvert.round(MAX_DBL_DIGITS+3); uprv_decNumberToString(numToConvert.fDecNumber, s); // TODO: how many extra digits should be included for an accurate conversion? } else { uprv_decNumberToString(this->fDecNumber, s); } U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); if (decimalSeparator != '.') { char *decimalPt = strchr(s, '.'); if (decimalPt != NULL) { *decimalPt = decimalSeparator; } } char *end = NULL; tDouble = uprv_strtod(s, &end); } { Mutex mutex; DigitList *nonConstThis = const_cast<DigitList *>(this); nonConstThis->internalSetDouble(tDouble); gDecimal = decimalSeparator; } return tDouble; }
// populatePower10 grabs data for a particular power of 10 from CLDR. // The loaded data is stored in result. static void populatePower10(const UResourceBundle* power10Bundle, CDFLocaleStyleData* result, UErrorCode& status) { if (U_FAILURE(status)) { return; } char* endPtr = NULL; double power10 = uprv_strtod(ures_getKey(power10Bundle), &endPtr); if (*endPtr != 0) { status = U_INTERNAL_PROGRAM_ERROR; return; } int32_t log10Value = computeLog10(power10, FALSE); // Silently ignore divisors that are too big. if (log10Value == MAX_DIGITS) { return; } int32_t size = ures_getSize(power10Bundle); int32_t numZeros = 0; UBool otherVariantDefined = FALSE; UResourceBundle* variantBundle = NULL; // Iterate over all the plural variants for the power of 10 for (int32_t i = 0; i < size; ++i) { variantBundle = ures_getByIndex(power10Bundle, i, variantBundle, &status); if (U_FAILURE(status)) { ures_close(variantBundle); return; } const char* variant = ures_getKey(variantBundle); int32_t resLen; const UChar* formatStrP = ures_getString(variantBundle, &resLen, &status); if (U_FAILURE(status)) { ures_close(variantBundle); return; } UnicodeString formatStr(false, formatStrP, resLen); if (uprv_strcmp(variant, gOther) == 0) { otherVariantDefined = TRUE; } int32_t nz = populatePrefixSuffix( variant, log10Value, formatStr, result->unitsByVariant, status); if (U_FAILURE(status)) { ures_close(variantBundle); return; } if (nz != numZeros) { // We expect all format strings to have the same number of 0's // left of the decimal point. if (numZeros != 0) { status = U_INTERNAL_PROGRAM_ERROR; ures_close(variantBundle); return; } numZeros = nz; } } ures_close(variantBundle); // We expect to find an OTHER variant for each power of 10. if (!otherVariantDefined) { status = U_INTERNAL_PROGRAM_ERROR; return; } double divisor = power10; for (int32_t i = 1; i < numZeros; ++i) { divisor /= 10.0; } result->divisors[log10Value] = divisor; }
void MessagePattern::parseDouble(int32_t start, int32_t limit, UBool allowInfinity, UParseError *parseError, UErrorCode &errorCode) { if(U_FAILURE(errorCode)) { return; } U_ASSERT(start<limit); // fake loop for easy exit and single throw statement for(;;) { /*loop doesn't iterate*/ // fast path for small integers and infinity int32_t value=0; int32_t isNegative=0; // not boolean so that we can easily add it to value int32_t index=start; UChar c=msg.charAt(index++); if(c==u_minus) { isNegative=1; if(index==limit) { break; // no number } c=msg.charAt(index++); } else if(c==u_plus) { if(index==limit) { break; // no number } c=msg.charAt(index++); } if(c==0x221e) { // infinity if(allowInfinity && index==limit) { double infinity=uprv_getInfinity(); addArgDoublePart( isNegative!=0 ? -infinity : infinity, start, limit-start, errorCode); return; } else { break; } } // try to parse the number as a small integer but fall back to a double while('0'<=c && c<='9') { value=value*10+(c-'0'); if(value>(Part::MAX_VALUE+isNegative)) { break; // not a small-enough integer } if(index==limit) { addPart(UMSGPAT_PART_TYPE_ARG_INT, start, limit-start, isNegative!=0 ? -value : value, errorCode); return; } c=msg.charAt(index++); } // Let Double.parseDouble() throw a NumberFormatException. char numberChars[128]; int32_t capacity=(int32_t)sizeof(numberChars); int32_t length=limit-start; if(length>=capacity) { break; // number too long } msg.extract(start, length, numberChars, capacity, US_INV); if((int32_t)uprv_strlen(numberChars)<length) { break; // contains non-invariant character that was turned into NUL } char *end; double numericValue=uprv_strtod(numberChars, &end); if(end!=(numberChars+length)) { break; // parsing error } addArgDoublePart(numericValue, start, length, errorCode); return; } setParseError(parseError, start /*, limit*/); // Bad syntax for numeric value. errorCode=U_PATTERN_SYNTAX_ERROR; return; }