]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/ucurr.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / i18n / ucurr.cpp
index 2bd08026215190f23428cd5741614439895a8a90..d2b4b2fe70cf9673e6a83ef982537446c4754779 100644 (file)
 #include "ucln_in.h"
 #include "uenumimp.h"
 #include "uhash.h"
 #include "ucln_in.h"
 #include "uenumimp.h"
 #include "uhash.h"
+#include "hash.h"
 #include "uresimp.h"
 #include "ulist.h"
 #include "ureslocs.h"
 
 #include "uresimp.h"
 #include "ulist.h"
 #include "ureslocs.h"
 
-// #define UCURR_DEBUG 1
+//#define UCURR_DEBUG_EQUIV 1
+#ifdef UCURR_DEBUG_EQUIV
+#include "stdio.h"
+#endif
+//#define UCURR_DEBUG 1
 #ifdef UCURR_DEBUG
 #include "stdio.h"
 #endif
 #ifdef UCURR_DEBUG
 #include "stdio.h"
 #endif
@@ -45,7 +50,7 @@ typedef struct IsoCodeEntry {
 // defaults encoded in the meta data resource bundle.  If there is a
 // configuration/build error and these are not available, we use these
 // hard-coded defaults (which should be identical).
 // defaults encoded in the meta data resource bundle.  If there is a
 // configuration/build error and these are not available, we use these
 // hard-coded defaults (which should be identical).
-static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
+static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 };
 
 // POW10[i] = 10^i, i=0..MAX_POW10
 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
 
 // POW10[i] = 10^i, i=0..MAX_POW10
 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
@@ -53,6 +58,14 @@ static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
 
 static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
 
 
 static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
 
+// Defines equivalent currency symbols.
+static const char *EQUIV_CURRENCY_SYMBOLS[][2] = {
+    {"\\u00a5", "\\uffe5"},
+    {"$", "\\ufe69"},
+    {"$", "\\uff04"},
+    {"\\u20a8", "\\u20b9"},
+    {"\\u00a3", "\\u20a4"}};
+
 #define ISO_CURRENCY_CODE_LENGTH 3
 
 //------------------------------------------------------------
 #define ISO_CURRENCY_CODE_LENGTH 3
 
 //------------------------------------------------------------
@@ -99,10 +112,129 @@ static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
 
 // ISO codes mapping table
 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
 
 // ISO codes mapping table
-static UHashtable* gIsoCodes = NULL;
-static UBool gIsoCodesInitialized = FALSE;
+static const UHashtable* gIsoCodes = NULL;
+static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
+
+// Currency symbol equivalances
+static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
+static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
+
+// EquivIterator iterates over all strings that are equivalent to a given
+// string, s. Note that EquivIterator will never yield s itself.
+class EquivIterator : icu::UMemory {
+public:
+    // Constructor. hash stores the equivalence relationships; s is the string
+    // for which we find equivalent strings.
+    inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s)
+        : _hash(hash) { 
+        _start = _current = &s;
+    }
+    inline ~EquivIterator() { }
+
+    // next returns the next equivalent string or NULL if there are no more.
+    // If s has no equivalent strings, next returns NULL on the first call.
+    const icu::UnicodeString *next();
+private:
+    const icu::Hashtable& _hash;
+    const icu::UnicodeString* _start;
+    const icu::UnicodeString* _current;
+};
 
 
-static UMutex gIsoCodesLock = U_MUTEX_INITIALIZER;
+const icu::UnicodeString *
+EquivIterator::next() {
+    const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current);
+    if (_next == NULL) {
+        U_ASSERT(_current == _start);
+        return NULL;
+    }
+    if (*_next == *_start) {
+        return NULL;
+    }
+    _current = _next;
+    return _next;
+}
+
+// makeEquivalent makes lhs and rhs equivalent by updating the equivalence
+// relations in hash accordingly.
+static void makeEquivalent(
+    const icu::UnicodeString &lhs,
+    const icu::UnicodeString &rhs,
+    icu::Hashtable* hash, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (lhs == rhs) {
+        // already equivalent
+        return;
+    }
+    EquivIterator leftIter(*hash, lhs);
+    EquivIterator rightIter(*hash, rhs);
+    const icu::UnicodeString *firstLeft = leftIter.next();
+    const icu::UnicodeString *firstRight = rightIter.next();
+    const icu::UnicodeString *nextLeft = firstLeft;
+    const icu::UnicodeString *nextRight = firstRight;
+    while (nextLeft != NULL && nextRight != NULL) {
+        if (*nextLeft == rhs || *nextRight == lhs) {
+            // Already equivalent
+            return;
+        }
+        nextLeft = leftIter.next();
+        nextRight = rightIter.next();
+    }
+    // Not equivalent. Must join.
+    icu::UnicodeString *newFirstLeft;
+    icu::UnicodeString *newFirstRight;
+    if (firstRight == NULL && firstLeft == NULL) {
+        // Neither lhs or rhs belong to an equivalence circle, so we form
+        // a new equivalnce circle of just lhs and rhs.
+        newFirstLeft = new icu::UnicodeString(rhs);
+        newFirstRight = new icu::UnicodeString(lhs);
+    } else if (firstRight == NULL) {
+        // lhs belongs to an equivalence circle, but rhs does not, so we link
+        // rhs into lhs' circle.
+        newFirstLeft = new icu::UnicodeString(rhs);
+        newFirstRight = new icu::UnicodeString(*firstLeft);
+    } else if (firstLeft == NULL) {
+        // rhs belongs to an equivlance circle, but lhs does not, so we link
+        // lhs into rhs' circle.
+        newFirstLeft = new icu::UnicodeString(*firstRight);
+        newFirstRight = new icu::UnicodeString(lhs);
+    } else {
+        // Both lhs and rhs belong to different equivalnce circles. We link
+        // them together to form one single, larger equivalnce circle.
+        newFirstLeft = new icu::UnicodeString(*firstRight);
+        newFirstRight = new icu::UnicodeString(*firstLeft);
+    }
+    if (newFirstLeft == NULL || newFirstRight == NULL) {
+        delete newFirstLeft;
+        delete newFirstRight;
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    hash->put(lhs, (void *) newFirstLeft, status);
+    hash->put(rhs, (void *) newFirstRight, status);
+}
+
+// countEquivalent counts how many strings are equivalent to s.
+// hash stores all the equivalnce relations.
+// countEquivalent does not include s itself in the count.
+static int32_t countEquivalent(const icu::Hashtable &hash, const icu::UnicodeString &s) {
+    int32_t result = 0;
+    EquivIterator iter(hash, s);
+    while (iter.next() != NULL) {
+        ++result;
+    }
+#ifdef UCURR_DEBUG_EQUIV
+ {
+   char tmp[200];
+   s.extract(0,s.length(),tmp, "UTF-8");
+   printf("CountEquivalent('%s') = %d\n", tmp, result);
+ }
+#endif
+    return result;
+}
+
+static const icu::Hashtable* getCurrSymbolsEquiv();
 
 //------------------------------------------------------------
 // Code
 
 //------------------------------------------------------------
 // Code
@@ -114,11 +246,22 @@ static UBool U_CALLCONV
 isoCodes_cleanup(void)
 {
     if (gIsoCodes != NULL) {
 isoCodes_cleanup(void)
 {
     if (gIsoCodes != NULL) {
-        uhash_close(gIsoCodes);
+        uhash_close(const_cast<UHashtable *>(gIsoCodes));
         gIsoCodes = NULL;
     }
         gIsoCodes = NULL;
     }
-    gIsoCodesInitialized = FALSE;
+    gIsoCodesInitOnce.reset();
+    return TRUE;
+}
 
 
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV 
+currSymbolsEquiv_cleanup(void)
+{
+    delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv);
+    gCurrSymbolsEquiv = NULL;
+    gCurrSymbolsEquivInitOnce.reset();
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -131,6 +274,15 @@ deleteIsoCodeEntry(void *obj) {
     uprv_free(entry);
 }
 
     uprv_free(entry);
 }
 
+/**
+ * Deleter for gCurrSymbolsEquiv.
+ */
+static void U_CALLCONV
+deleteUnicode(void *obj) {
+    icu::UnicodeString *entry = (icu::UnicodeString*)obj;
+    delete entry;
+}
+
 /**
  * Unfortunately, we have to convert the UChar* currency code to char*
  * to use it as a resource key.
 /**
  * Unfortunately, we have to convert the UChar* currency code to char*
  * to use it as a resource key.
@@ -144,9 +296,11 @@ myUCharsToChars(char* resultOfLen4, const UChar* currency) {
 
 /**
  * Internal function to look up currency data.  Result is an array of
 
 /**
  * Internal function to look up currency data.  Result is an array of
- * two integers.  The first is the fraction digits.  The second is the
+ * four integers.  The first is the fraction digits.  The second is the
  * rounding increment, or 0 if none.  The rounding increment is in
  * rounding increment, or 0 if none.  The rounding increment is in
- * units of 10^(-fraction_digits).
+ * units of 10^(-fraction_digits).  The third and fourth are the same
+ * except that they are those used in cash transations ( cashDigits
+ * and cashRounding ).
  */
 static const int32_t*
 _findMetaData(const UChar* currency, UErrorCode& ec) {
  */
 static const int32_t*
 _findMetaData(const UChar* currency, UErrorCode& ec) {
@@ -187,7 +341,7 @@ _findMetaData(const UChar* currency, UErrorCode& ec) {
 
     int32_t len;
     const int32_t *data = ures_getIntVector(rb, &len, &ec);
 
     int32_t len;
     const int32_t *data = ures_getIntVector(rb, &len, &ec);
-    if (U_FAILURE(ec) || len != 2) {
+    if (U_FAILURE(ec) || len != 4) {
         // Config/build error; return hard-coded defaults
         if (U_SUCCESS(ec)) {
             ec = U_INVALID_FORMAT_ERROR;
         // Config/build error; return hard-coded defaults
         if (U_SUCCESS(ec)) {
             ec = U_INVALID_FORMAT_ERROR;
@@ -379,6 +533,7 @@ static UBool U_CALLCONV currency_cleanup(void) {
      */
     currency_cache_cleanup();
     isoCodes_cleanup();
      */
     currency_cache_cleanup();
     isoCodes_cleanup();
+    currSymbolsEquiv_cleanup();
 
     return TRUE;
 }
 
     return TRUE;
 }
@@ -745,6 +900,7 @@ getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_
     const UChar* s = NULL;
     char locale[ULOC_FULLNAME_CAPACITY];
     uprv_strcpy(locale, loc);
     const UChar* s = NULL;
     char locale[ULOC_FULLNAME_CAPACITY];
     uprv_strcpy(locale, loc);
+    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
     for (;;) {
         UErrorCode ec2 = U_ZERO_ERROR;
         // TODO: ures_openDirect?
     for (;;) {
         UErrorCode ec2 = U_ZERO_ERROR;
         // TODO: ures_openDirect?
@@ -770,6 +926,9 @@ getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_
                 *total_currency_symbol_count += fmt_count;
             } else {
                 ++(*total_currency_symbol_count);  // currency symbol
                 *total_currency_symbol_count += fmt_count;
             } else {
                 ++(*total_currency_symbol_count);  // currency symbol
+                if (currencySymbolsEquiv != NULL) {
+                    *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
+                }
             }
 
             ++(*total_currency_symbol_count); // iso code
             }
 
             ++(*total_currency_symbol_count); // iso code
@@ -826,6 +985,7 @@ collectCurrencyNames(const char* locale,
                      int32_t* total_currency_symbol_count, 
                      UErrorCode& ec) {
     U_NAMESPACE_USE
                      int32_t* total_currency_symbol_count, 
                      UErrorCode& ec) {
     U_NAMESPACE_USE
+    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
     // Look up the Currencies resource for the given locale.
     UErrorCode ec2 = U_ZERO_ERROR;
 
     // Look up the Currencies resource for the given locale.
     UErrorCode ec2 = U_ZERO_ERROR;
 
@@ -905,6 +1065,17 @@ collectCurrencyNames(const char* locale,
                 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
                 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
                 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
                 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
                 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
                 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
+                // Add equivalent symbols
+                if (currencySymbolsEquiv != NULL) {
+                    EquivIterator iter(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
+                    const UnicodeString *symbol;
+                    while ((symbol = iter.next()) != NULL) {
+                        (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
+                        (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*) symbol->getBuffer();
+                        (*currencySymbols)[*total_currency_symbol_count].flag = 0;
+                        (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length();
+                    }
+                }
             }
 
             // Add currency long name.
             }
 
             // Add currency long name.
@@ -982,22 +1153,20 @@ collectCurrencyNames(const char* locale,
     for (int32_t index = 0; index < *total_currency_name_count; ++index) {
         printf("index: %d\n", index);
         printf("iso: %s\n", (*currencyNames)[index].IsoCode);
     for (int32_t index = 0; index < *total_currency_name_count; ++index) {
         printf("index: %d\n", index);
         printf("iso: %s\n", (*currencyNames)[index].IsoCode);
-        printf("currencyName:");
-        for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
-            printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
-        }
-        printf("\n");
+        char curNameBuf[1024];
+        memset(curNameBuf, 0, 1024);
+        u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen);
+        printf("currencyName: %s\n", curNameBuf);
         printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
     }
     printf("currency symbol count: %d\n", *total_currency_symbol_count);
     for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
         printf("index: %d\n", index);
         printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
         printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
     }
     printf("currency symbol count: %d\n", *total_currency_symbol_count);
     for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
         printf("index: %d\n", index);
         printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
-        printf("currencySymbol:");
-        for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
-            printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
-        }
-        printf("\n");
+        char curNameBuf[1024];
+        memset(curNameBuf, 0, 1024);
+        u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen);
+        printf("currencySymbol: %s\n", curNameBuf);
         printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
     }
 #endif
         printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
     }
 #endif
@@ -1227,6 +1396,8 @@ static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
 // It is a simple round-robin replacement strategy.
 static int8_t currentCacheEntryIndex = 0;
 
 // It is a simple round-robin replacement strategy.
 static int8_t currentCacheEntryIndex = 0;
 
+static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
+
 // Cache deletion
 static void
 deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
 // Cache deletion
 static void
 deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
@@ -1280,9 +1451,9 @@ uprv_parseCurrency(const char* locale,
     CurrencyNameStruct* currencySymbols = NULL;
     CurrencyNameCacheEntry* cacheEntry = NULL;
 
     CurrencyNameStruct* currencySymbols = NULL;
     CurrencyNameCacheEntry* cacheEntry = NULL;
 
-    umtx_lock(NULL);
+    umtx_lock(&gCurrencyCacheMutex);
     // in order to handle racing correctly,
     // in order to handle racing correctly,
-    // not putting 'search' in a separate function and using UMTX.
+    // not putting 'search' in a separate function.
     int8_t  found = -1;
     for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
         if (currCache[i]!= NULL &&
     int8_t  found = -1;
     for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
         if (currCache[i]!= NULL &&
@@ -1299,13 +1470,13 @@ uprv_parseCurrency(const char* locale,
         total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
         ++(cacheEntry->refCount);
     }
         total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
         ++(cacheEntry->refCount);
     }
-    umtx_unlock(NULL);
+    umtx_unlock(&gCurrencyCacheMutex);
     if (found == -1) {
         collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
         if (U_FAILURE(ec)) {
             return;
         }
     if (found == -1) {
         collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
         if (U_FAILURE(ec)) {
             return;
         }
-        umtx_lock(NULL);
+        umtx_lock(&gCurrencyCacheMutex);
         // check again.
         int8_t  found = -1;
         for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
         // check again.
         int8_t  found = -1;
         for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
@@ -1350,7 +1521,7 @@ uprv_parseCurrency(const char* locale,
             total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
             ++(cacheEntry->refCount);
         }
             total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
             ++(cacheEntry->refCount);
         }
-        umtx_unlock(NULL);
+        umtx_unlock(&gCurrencyCacheMutex);
     }
 
     int32_t start = pos.getIndex();
     }
 
     int32_t start = pos.getIndex();
@@ -1383,6 +1554,9 @@ uprv_parseCurrency(const char* locale,
 
 #ifdef UCURR_DEBUG
     printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
 
 #ifdef UCURR_DEBUG
     printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
+    if(matchIndexInSymbol != -1) {
+      printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode);
+    }
 #endif
 
     if (max >= maxInSymbol && matchIndex != -1) {
 #endif
 
     if (max >= maxInSymbol && matchIndex != -1) {
@@ -1394,12 +1568,12 @@ uprv_parseCurrency(const char* locale,
     } 
 
     // decrease reference count
     } 
 
     // decrease reference count
-    umtx_lock(NULL);
+    umtx_lock(&gCurrencyCacheMutex);
     --(cacheEntry->refCount);
     if (cacheEntry->refCount == 0) {  // remove 
         deleteCacheEntry(cacheEntry);
     }
     --(cacheEntry->refCount);
     if (cacheEntry->refCount == 0) {  // remove 
         deleteCacheEntry(cacheEntry);
     }
-    umtx_unlock(NULL);
+    umtx_unlock(&gCurrencyCacheMutex);
 }
 
 
 }
 
 
@@ -1842,7 +2016,7 @@ ucurr_closeCurrencyList(UEnumeration *enumerator) {
 }
 
 static void U_CALLCONV
 }
 
 static void U_CALLCONV
-ucurr_createCurrencyList(UErrorCode* status){
+ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
     UErrorCode localStatus = U_ZERO_ERROR;
 
     // Look up the CurrencyMap element in the root bundle.
     UErrorCode localStatus = U_ZERO_ERROR;
 
     // Look up the CurrencyMap element in the root bundle.
@@ -1908,7 +2082,7 @@ ucurr_createCurrencyList(UErrorCode* status){
                     entry->to = toDate;
 
                     localStatus = U_ZERO_ERROR;
                     entry->to = toDate;
 
                     localStatus = U_ZERO_ERROR;
-                    uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus);
+                    uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
                 }
             } else {
                 *status = localStatus;
                 }
             } else {
                 *status = localStatus;
@@ -1933,36 +2107,70 @@ static const UEnumeration gEnumCurrencyList = {
 };
 U_CDECL_END
 
 };
 U_CDECL_END
 
-U_CAPI UBool U_EXPORT2
-ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
-    UErrorCode status = U_ZERO_ERROR;
-    UBool initialized;
-    UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized);
 
 
-    if (!initialized) {
-        umtx_lock(&gIsoCodesLock);
-        gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
-        if (U_FAILURE(status)) {
-            umtx_unlock(&gIsoCodesLock);
-            return FALSE;
-        }
-        uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry);
+static void U_CALLCONV initIsoCodes(UErrorCode &status) {
+    U_ASSERT(gIsoCodes == NULL);
+    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
 
 
-        ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
-        ucurr_createCurrencyList(&status);
+    UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
+
+    ucurr_createCurrencyList(isoCodes, &status);
+    if (U_FAILURE(status)) {
+        uhash_close(isoCodes);
+        return;
+    }
+    gIsoCodes = isoCodes;  // Note: gIsoCodes is const. Once set up here it is never altered,
+                           //       and read only access is safe without synchronization.
+}
+
+static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    int32_t length = sizeof(EQUIV_CURRENCY_SYMBOLS) / sizeof(EQUIV_CURRENCY_SYMBOLS[0]);
+    for (int32_t i = 0; i < length; ++i) {
+        icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV);
+        icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV);
+        makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status);
         if (U_FAILURE(status)) {
         if (U_FAILURE(status)) {
-            umtx_unlock(&gIsoCodesLock);
-            return FALSE;
+            return;
         }
         }
+    }
+}
+
+static void U_CALLCONV initCurrSymbolsEquiv() {
+    U_ASSERT(gCurrSymbolsEquiv == NULL);
+    UErrorCode status = U_ZERO_ERROR;
+    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
+    icu::Hashtable *temp = new icu::Hashtable(status);
+    if (temp == NULL) {
+        return;
+    }
+    if (U_FAILURE(status)) {
+        delete temp;
+        return;
+    }
+    temp->setValueDeleter(deleteUnicode);
+    populateCurrSymbolsEquiv(temp, status);
+    if (U_FAILURE(status)) {
+        delete temp;
+        return;
+    }
+    gCurrSymbolsEquiv = temp;
+}
 
 
-        gIsoCodesInitialized = TRUE;
-        umtx_unlock(&gIsoCodesLock);
+U_CAPI UBool U_EXPORT2
+ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
+    umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
+    if (U_FAILURE(*eErrorCode)) {
+        return FALSE;
     }
 
     }
 
-    umtx_lock(&gIsoCodesLock);
     IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
     IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
-    umtx_unlock(&gIsoCodesLock);
-
     if (result == NULL) {
         return FALSE;
     } else if (from > to) {
     if (result == NULL) {
         return FALSE;
     } else if (from > to) {
@@ -1971,10 +2179,14 @@ ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eError
     } else if  ((from > result->to) || (to < result->from)) {
         return FALSE;
     }
     } else if  ((from > result->to) || (to < result->from)) {
         return FALSE;
     }
-
     return TRUE;
 }
 
     return TRUE;
 }
 
+static const icu::Hashtable* getCurrSymbolsEquiv() {
+    umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv);
+    return gCurrSymbolsEquiv;
+}
+
 U_CAPI UEnumeration * U_EXPORT2
 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
     UEnumeration *myEnum = NULL;
 U_CAPI UEnumeration * U_EXPORT2
 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
     UEnumeration *myEnum = NULL;