| 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; | 
| } | 
|  |