]> granicus.if.org Git - icu/commitdiff
ICU-10232 DigitList to use strtod_l instead of strtod with cached host decimal point...
authorYoshito Umaoka <y.umaoka@gmail.com>
Fri, 2 Sep 2016 20:58:05 +0000 (20:58 +0000)
committerYoshito Umaoka <y.umaoka@gmail.com>
Fri, 2 Sep 2016 20:58:05 +0000 (20:58 +0000)
X-SVN-Rev: 39124

icu4c/source/configure
icu4c/source/configure.ac
icu4c/source/i18n/digitlst.cpp
icu4c/source/i18n/digitlst.h
icu4c/source/i18n/ucln_in.h
icu4c/source/i18n/visibledigits.cpp
icu4c/source/test/perf/DateFmtPerf/DateFmtPerf.vcxproj

index afd527d1a22924758885110e70b78b2bcb2154a4..4cd3586d23b04421b24c36484965c9ae5cd293ac 100755 (executable)
@@ -657,6 +657,7 @@ U_HAVE_EXTRAS
 EXTRAS_TRUE
 U_HAVE_WCSCPY
 U_HAVE_WCHAR_H
+U_HAVE_STRTOD_L
 U_TIMEZONE
 U_HAVE_TIMEZONE
 U_TZNAME
@@ -753,6 +754,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -856,6 +858,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1108,6 +1111,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1245,7 +1257,7 @@ fi
 for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir
+               libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1398,6 +1410,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -7051,6 +7064,20 @@ fi
 
 
 
+ac_fn_c_check_func "$LINENO" "strtod_l" "ac_cv_func_strtod_l"
+if test "x$ac_cv_func_strtod_l" = xyes; then :
+
+fi
+
+if test x$ac_cv_func_strtod_l = xyes
+then
+     U_HAVE_STRTOD_L=1
+else
+     CONFIG_CPPFLAGS="${CONFIG_CPPFLAGS} -DU_HAVE_STRTOD_L=0"
+     U_HAVE_STRTOD_L=0
+fi
+
+
 # Checks for typedefs
 ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default"
 if test "x$ac_cv_type_int8_t" = xyes; then :
index fe71065b08953ac6ca1e60ecb707102d0d10962e..76aa00e1976846dec56832b54e9bbb7caaaf978c 100644 (file)
@@ -893,6 +893,16 @@ fi
 AC_SUBST(U_HAVE_TIMEZONE)
 AC_SUBST(U_TIMEZONE)
 
+AC_CHECK_FUNC(strtod_l)
+if test x$ac_cv_func_strtod_l = xyes
+then
+     U_HAVE_STRTOD_L=1
+else
+     CONFIG_CPPFLAGS="${CONFIG_CPPFLAGS} -DU_HAVE_STRTOD_L=0"
+     U_HAVE_STRTOD_L=0
+fi
+AC_SUBST(U_HAVE_STRTOD_L)
+
 # Checks for typedefs
 AC_CHECK_TYPE(int8_t,signed char)
 AC_CHECK_TYPE(uint8_t,unsigned char)
index 32fb9c40bca93de3b1404f265412e4701e0f2944..4e0f5df7f7541c1d0c9771e2e7054964f458fb25 100644 (file)
@@ -37,6 +37,8 @@
 #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>
@@ -397,27 +399,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,24 +411,11 @@ char DigitList::getStrtodDecimalSeparator() {
 double
 DigitList::getDouble() const
 {
-    static char gDecimal = 0;
-    char decimalSeparator;
     {
         Mutex mutex;
         if (fHave == kDouble) {
             return fUnion.fDouble;
         }
-        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;
@@ -484,25 +452,77 @@ 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 !defined(U_HAVE_STRTOD_L)
+#  if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM_HAS_WIN32_API
+#    define U_HAVE_STRTOD_L 1
+#  else
+#    define U_HAVE_STRTOD_L 0
+#  endif
+#endif
+
+#if U_HAVE_STRTOD_L && U_PLATFORM_HAS_WIN32_API
+#define locale_t _locale_t
+#define newlocale(cat, loc, base) _create_locale(cat, loc)
+#define freelocale _free_locale
+#define strtod_l _strtod_l
+#endif
+
+#if U_HAVE_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_HAVE_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_HAVE_STRTOD_L
+    gCLocale = newlocale(LC_ALL, "C", (locale_t)0);
+#endif
+}
+U_CDECL_END
+
+double
+DigitList::decimalStrToDouble(char *decstr, char **end) {
+    umtx_initOnce(gCLocaleInitOnce, &initCLocale);
+#if U_HAVE_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
+}
+
 // -------------------------------------
 
 /**
index 0e781c021fde1b6ff454892111f86b1af9b27ba0..45cb49a64418bd77665029444c4e259b289dbda8 100644 (file)
@@ -495,7 +495,8 @@ private:
     static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
     static inline void U_EXPORT2 operator delete(void *ptr )  U_NO_THROW { ::operator delete(ptr); };
 #endif
-    static char U_EXPORT2 getStrtodDecimalSeparator();
+
+    static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end);
 
     /**
      * Placement new for stack usage
index bbb05af9bd2f2ebfe8ce62631054b041f4bc9106..b5069e17c036d377172097539ea4a81196a7d405 100644 (file)
@@ -42,6 +42,7 @@ typedef enum ECleanupI18NType {
     UCLN_I18N_TIMEZONENAMES,
     UCLN_I18N_ZONEMETA,
     UCLN_I18N_TIMEZONE,
+    UCLN_I18N_DIGITLIST,
     UCLN_I18N_DECFMT,
     UCLN_I18N_NUMFMT,
     UCLN_I18N_ALLOWED_HOUR_FORMATS,
index 5ab8b5e416bbfd7235156723d56c298f40618cd8..9fbcac7b53997da82fcc10e49afe2bf64d31c732 100644 (file)
@@ -114,15 +114,8 @@ double VisibleDigits::computeAbsDoubleValue() const {
     char str[MAX_DBL_DIGITS+18];
     uprv_decNumberToString(numberPtr, str);
     U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18);
-    char decimalSeparator = DigitList::getStrtodDecimalSeparator();
-    if (decimalSeparator != '.') {
-        char *decimalPt = strchr(str, '.');
-        if (decimalPt != NULL) {
-            *decimalPt = decimalSeparator;
-        }
-    }
     char *unused = NULL;
-    return uprv_strtod(str, &unused);
+    return DigitList::decimalStrToDouble(str, &unused);
 }
 
 void VisibleDigits::getFixedDecimal(
index ab511a77bd6b499d4b42b651d81cc677f426032c..609f3031256551ea3879d9bd46486f5b39a58791 100644 (file)
@@ -45,8 +45,6 @@
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\x86\$(Configuration)\</OutDir>\r
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>\r
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(VCInstallDir)bin;$(WindowsSdkDir)bin\NETFX 4.0 Tools;$(WindowsSdkDir)bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)\bin;$(MSBuildToolsPath32);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);..\..\..\..\bin;$(PATH);</ExecutablePath>\r
-    <ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(VCInstallDir)bin;$(WindowsSdkDir)bin\NETFX 4.0 Tools;$(WindowsSdkDir)bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)\bin;$(MSBuildToolsPath32);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);..\..\..\..\bin;$(PATH);</ExecutablePath>\r
   </PropertyGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
     <ClCompile>\r