| Index: source/i18n/anytrans.cpp
|
| diff --git a/source/i18n/anytrans.cpp b/source/i18n/anytrans.cpp
|
| index c3b3b67c25ce89940e210fcc4375590bf99834d0..695a9390b681c0355512d9b1c2441e1d0f5a30f3 100644
|
| --- a/source/i18n/anytrans.cpp
|
| +++ b/source/i18n/anytrans.cpp
|
| @@ -1,6 +1,6 @@
|
| /*
|
| *****************************************************************
|
| -* Copyright (c) 2002-2011, International Business Machines Corporation
|
| +* Copyright (c) 2002-2014, International Business Machines Corporation
|
| * and others. All Rights Reserved.
|
| *****************************************************************
|
| * Date Name Description
|
| @@ -14,13 +14,15 @@
|
|
|
| #include "unicode/uobject.h"
|
| #include "unicode/uscript.h"
|
| -#include "nultrans.h"
|
| +
|
| #include "anytrans.h"
|
| -#include "uvector.h"
|
| -#include "tridpars.h"
|
| #include "hash.h"
|
| +#include "mutex.h"
|
| +#include "nultrans.h"
|
| #include "putilimp.h"
|
| +#include "tridpars.h"
|
| #include "uinvchar.h"
|
| +#include "uvector.h"
|
|
|
| //------------------------------------------------------------
|
| // Constants
|
| @@ -39,7 +41,7 @@ U_CDECL_BEGIN
|
| */
|
| static void U_CALLCONV
|
| _deleteTransliterator(void *obj) {
|
| - delete (icu::Transliterator*) obj;
|
| + delete (icu::Transliterator*) obj;
|
| }
|
| U_CDECL_END
|
|
|
| @@ -85,7 +87,7 @@ public:
|
| * The end of the run, exclusive, valid after next() returns.
|
| */
|
| int32_t limit;
|
| -
|
| +
|
| /**
|
| * Constructs a run iterator over the given text from start
|
| * (inclusive) to limit (exclusive).
|
| @@ -180,7 +182,7 @@ AnyTransliterator::AnyTransliterator(const UnicodeString& id,
|
| UScriptCode theTargetScript,
|
| UErrorCode& ec) :
|
| Transliterator(id, NULL),
|
| - targetScript(theTargetScript)
|
| + targetScript(theTargetScript)
|
| {
|
| cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &ec);
|
| if (U_FAILURE(ec)) {
|
| @@ -239,7 +241,7 @@ void AnyTransliterator::handleTransliterate(Replaceable& text, UTransPosition& p
|
| // Try to instantiate transliterator from it.scriptCode to
|
| // our target or target/variant
|
| Transliterator* t = getTransliterator(it.scriptCode);
|
| -
|
| +
|
| if (t == NULL) {
|
| // We have no transliterator. Do nothing, but keep
|
| // pos.start up to date.
|
| @@ -251,7 +253,7 @@ void AnyTransliterator::handleTransliterate(Replaceable& text, UTransPosition& p
|
| // a non-incremental transliteration. Otherwise do an
|
| // incremental one.
|
| UBool incremental = isIncremental && (it.limit >= allLimit);
|
| -
|
| +
|
| pos.start = uprv_max(allStart, it.start);
|
| pos.limit = uprv_min(allLimit, it.limit);
|
| int32_t limit = pos.limit;
|
| @@ -275,17 +277,21 @@ Transliterator* AnyTransliterator::getTransliterator(UScriptCode source) const {
|
| return NULL;
|
| }
|
|
|
| - Transliterator* t = (Transliterator*) uhash_iget(cache, (int32_t) source);
|
| + Transliterator* t = NULL;
|
| + {
|
| + Mutex m(NULL);
|
| + t = (Transliterator*) uhash_iget(cache, (int32_t) source);
|
| + }
|
| if (t == NULL) {
|
| UErrorCode ec = U_ZERO_ERROR;
|
| UnicodeString sourceName(uscript_getName(source), -1, US_INV);
|
| UnicodeString id(sourceName);
|
| id.append(TARGET_SEP).append(target);
|
| -
|
| +
|
| t = Transliterator::createInstance(id, UTRANS_FORWARD, ec);
|
| if (U_FAILURE(ec) || t == NULL) {
|
| delete t;
|
| -
|
| +
|
| // Try to pivot around Latin, our most common script
|
| id = sourceName;
|
| id.append(LATIN_PIVOT, -1).append(target);
|
| @@ -297,10 +303,23 @@ Transliterator* AnyTransliterator::getTransliterator(UScriptCode source) const {
|
| }
|
|
|
| if (t != NULL) {
|
| - uhash_iput(cache, (int32_t) source, t, &ec);
|
| + Transliterator *rt = NULL;
|
| + {
|
| + Mutex m(NULL);
|
| + rt = static_cast<Transliterator *> (uhash_iget(cache, (int32_t) source));
|
| + if (rt == NULL) {
|
| + // Common case, no race to cache this new transliterator.
|
| + uhash_iput(cache, (int32_t) source, t, &ec);
|
| + } else {
|
| + // Race case, some other thread beat us to caching this transliterator.
|
| + Transliterator *temp = rt;
|
| + rt = t; // Our newly created transliterator that lost the race & now needs deleting.
|
| + t = temp; // The transliterator from the cache that we will return.
|
| + }
|
| + }
|
| + delete rt; // will be non-null only in case of races.
|
| }
|
| }
|
| -
|
| return t;
|
| }
|
|
|
| @@ -313,7 +332,7 @@ static UScriptCode scriptNameToCode(const UnicodeString& name) {
|
| UErrorCode ec = U_ZERO_ERROR;
|
| int32_t nameLen = name.length();
|
| UBool isInvariant = uprv_isInvariantUString(name.getBuffer(), nameLen);
|
| -
|
| +
|
| if (isInvariant) {
|
| name.extract(0, nameLen, buf, (int32_t)sizeof(buf), US_INV);
|
| buf[127] = 0; // Make sure that we NULL terminate the string.
|
| @@ -352,7 +371,7 @@ void AnyTransliterator::registerIDs() {
|
| if (seen.geti(target) != 0) continue;
|
| ec = U_ZERO_ERROR;
|
| seen.puti(target, 1, ec);
|
| -
|
| +
|
| // Get the script code for the target. If not a script, ignore.
|
| UScriptCode targetScript = scriptNameToCode(target);
|
| if (targetScript == USCRIPT_INVALID_CODE) continue;
|
| @@ -362,7 +381,7 @@ void AnyTransliterator::registerIDs() {
|
| for (int32_t v=0; v<variantCount; ++v) {
|
| UnicodeString variant;
|
| Transliterator::_getAvailableVariant(v, source, target, variant);
|
| -
|
| +
|
| UnicodeString id;
|
| TransliteratorIDParser::STVtoID(UnicodeString(TRUE, ANY, 3), target, variant, id);
|
| ec = U_ZERO_ERROR;
|
|
|