| Index: source/i18n/digitlst.cpp
|
| diff --git a/source/i18n/digitlst.cpp b/source/i18n/digitlst.cpp
|
| index bdd3c92bace6a5249a9a8b40b7d8c92c71d0a11d..e157a3f84c52d9fdc16c57ff7b83c4f1d2dd866d 100644
|
| --- a/source/i18n/digitlst.cpp
|
| +++ b/source/i18n/digitlst.cpp
|
| @@ -1,3 +1,5 @@
|
| +// Copyright (C) 2016 and later: Unicode, Inc. and others.
|
| +// License & terms of use: http://www.unicode.org/copyright.html
|
| /*
|
| **********************************************************************
|
| * Copyright (C) 1997-2015, International Business Machines
|
| @@ -27,6 +29,7 @@
|
| #include "digitlst.h"
|
|
|
| #if !UCONFIG_NO_FORMATTING
|
| +
|
| #include "unicode/putil.h"
|
| #include "charstr.h"
|
| #include "cmemory.h"
|
| @@ -35,12 +38,28 @@
|
| #include "putilimp.h"
|
| #include "uassert.h"
|
| #include "digitinterval.h"
|
| +#include "ucln_in.h"
|
| +#include "umutex.h"
|
| #include <stdlib.h>
|
| #include <limits.h>
|
| #include <string.h>
|
| #include <stdio.h>
|
| #include <limits>
|
|
|
| +#if !defined(U_USE_STRTOD_L)
|
| +# if U_PLATFORM_HAS_WIN32_API
|
| +# define U_USE_STRTOD_L 1
|
| +# elif defined(U_HAVE_STRTOD_L)
|
| +# define U_USE_STRTOD_L U_HAVE_STRTOD_L
|
| +# else
|
| +# define U_USE_STRTOD_L 0
|
| +# endif
|
| +#endif
|
| +
|
| +#if U_USE_STRTOD_L && !U_PLATFORM_HAS_WIN32_API
|
| +#include <xlocale.h>
|
| +#endif
|
| +
|
| // ***************************************************************************
|
| // class DigitList
|
| // A wrapper onto decNumber.
|
| @@ -118,9 +137,7 @@ DigitList::operator=(const DigitList& other)
|
| Mutex mutex;
|
|
|
| if(other.fHave==kDouble) {
|
| - fUnion.fDouble = other.fUnion.fDouble;
|
| - } else if(other.fHave==kInt64) {
|
| - fUnion.fInt64 = other.fUnion.fInt64;
|
| + fUnion.fDouble = other.fUnion.fDouble;
|
| }
|
| fHave = other.fHave;
|
| }
|
| @@ -397,27 +414,6 @@ DigitList::append(char digit)
|
| internalClear();
|
| }
|
|
|
| -char DigitList::getStrtodDecimalSeparator() {
|
| - // TODO: maybe use andy's pthread once.
|
| - static char gDecimal = 0;
|
| - char result;
|
| - {
|
| - Mutex mutex;
|
| - result = gDecimal;;
|
| - if (result == 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);
|
| - result = rep[2];
|
| - gDecimal = result;;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| // -------------------------------------
|
|
|
| /**
|
| @@ -430,26 +426,11 @@ char DigitList::getStrtodDecimalSeparator() {
|
| 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;
|
| @@ -486,25 +467,72 @@ DigitList::getDouble() const
|
| uprv_decNumberToString(this->fDecNumber, s.getAlias());
|
| }
|
| U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
|
| -
|
| - if (decimalSeparator != '.') {
|
| - char *decimalPt = strchr(s.getAlias(), '.');
|
| - if (decimalPt != NULL) {
|
| - *decimalPt = decimalSeparator;
|
| - }
|
| - }
|
| +
|
| char *end = NULL;
|
| - tDouble = uprv_strtod(s.getAlias(), &end);
|
| + tDouble = decimalStrToDouble(s.getAlias(), &end);
|
| }
|
| {
|
| Mutex mutex;
|
| DigitList *nonConstThis = const_cast<DigitList *>(this);
|
| nonConstThis->internalSetDouble(tDouble);
|
| - gDecimal = decimalSeparator;
|
| }
|
| return tDouble;
|
| }
|
|
|
| +#if U_USE_STRTOD_L && U_PLATFORM_HAS_WIN32_API
|
| +# define locale_t _locale_t
|
| +# define freelocale _free_locale
|
| +# define strtod_l _strtod_l
|
| +#endif
|
| +
|
| +#if U_USE_STRTOD_L
|
| +static locale_t gCLocale = (locale_t)0;
|
| +#endif
|
| +static icu::UInitOnce gCLocaleInitOnce = U_INITONCE_INITIALIZER;
|
| +
|
| +U_CDECL_BEGIN
|
| +// Cleanup callback func
|
| +static UBool U_CALLCONV digitList_cleanup(void)
|
| +{
|
| +#if U_USE_STRTOD_L
|
| + if (gCLocale != (locale_t)0) {
|
| + freelocale(gCLocale);
|
| + }
|
| +#endif
|
| + return TRUE;
|
| +}
|
| +// C Locale initialization func
|
| +static void U_CALLCONV initCLocale(void) {
|
| + ucln_i18n_registerCleanup(UCLN_I18N_DIGITLIST, digitList_cleanup);
|
| +#if U_USE_STRTOD_L
|
| +# if U_PLATFORM_HAS_WIN32_API
|
| + gCLocale = _create_locale(LC_ALL, "C");
|
| +# else
|
| + gCLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
|
| +# endif
|
| +#endif
|
| +}
|
| +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
|
| +}
|
| +
|
| // -------------------------------------
|
|
|
| /**
|
| @@ -537,9 +565,8 @@ int32_t DigitList::getLong() /*const*/
|
| * Return zero if the number cannot be represented.
|
| */
|
| int64_t DigitList::getInt64() /*const*/ {
|
| - if(fHave==kInt64) {
|
| - return fUnion.fInt64;
|
| - }
|
| + // TODO: fast conversion if fHave == fDouble
|
| +
|
| // Truncate if non-integer.
|
| // Return 0 if out of range.
|
| // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
|
| @@ -729,17 +756,6 @@ DigitList::set(int64_t source)
|
| internalSetDouble(static_cast<double>(source));
|
| }
|
|
|
| -/**
|
| - * Set an int64, with no decnumber
|
| - */
|
| -void
|
| -DigitList::setInteger(int64_t source)
|
| -{
|
| - fDecNumber=NULL;
|
| - internalSetInt64(source);
|
| -}
|
| -
|
| -
|
| // -------------------------------------
|
| /**
|
| * Set the DigitList from a decimal number string.
|
| @@ -750,7 +766,7 @@ DigitList::setInteger(int64_t source)
|
| * be acceptable for a public API.
|
| */
|
| void
|
| -DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) {
|
| +DigitList::set(StringPiece source, UErrorCode &status, uint32_t /*fastpathBits*/) {
|
| if (U_FAILURE(status)) {
|
| return;
|
| }
|
|
|