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