OLD | NEW |
1 /* | 1 /* |
2 ********************************************************************** | 2 ********************************************************************** |
3 * Copyright (c) 2002-2012, International Business Machines Corporation | 3 * Copyright (c) 2002-2014, International Business Machines Corporation |
4 * and others. All Rights Reserved. | 4 * and others. All Rights Reserved. |
5 ********************************************************************** | 5 ********************************************************************** |
6 * Date Name Description | 6 * Date Name Description |
7 * 01/14/2002 aliu Creation. | 7 * 01/14/2002 aliu Creation. |
8 ********************************************************************** | 8 ********************************************************************** |
9 */ | 9 */ |
10 | 10 |
11 #include "unicode/utypes.h" | 11 #include "unicode/utypes.h" |
12 | 12 |
13 #if !UCONFIG_NO_TRANSLITERATION | 13 #if !UCONFIG_NO_TRANSLITERATION |
14 | 14 |
15 #include "tridpars.h" | 15 #include "tridpars.h" |
16 #include "hash.h" | 16 #include "hash.h" |
17 #include "mutex.h" | 17 #include "mutex.h" |
| 18 #include "transreg.h" |
| 19 #include "uassert.h" |
18 #include "ucln_in.h" | 20 #include "ucln_in.h" |
19 #include "unicode/parsepos.h" | 21 #include "unicode/parsepos.h" |
20 #include "unicode/translit.h" | 22 #include "unicode/translit.h" |
21 #include "unicode/uchar.h" | 23 #include "unicode/uchar.h" |
22 #include "unicode/uniset.h" | 24 #include "unicode/uniset.h" |
23 #include "unicode/unistr.h" | 25 #include "unicode/unistr.h" |
24 #include "unicode/utrans.h" | 26 #include "unicode/utrans.h" |
25 #include "util.h" | 27 #include "util.h" |
26 #include "uvector.h" | 28 #include "uvector.h" |
27 | 29 |
28 U_NAMESPACE_BEGIN | 30 U_NAMESPACE_BEGIN |
29 | 31 |
30 static const UChar ID_DELIM = 0x003B; // ; | 32 static const UChar ID_DELIM = 0x003B; // ; |
31 static const UChar TARGET_SEP = 0x002D; // - | 33 static const UChar TARGET_SEP = 0x002D; // - |
32 static const UChar VARIANT_SEP = 0x002F; // / | 34 static const UChar VARIANT_SEP = 0x002F; // / |
33 static const UChar OPEN_REV = 0x0028; // ( | 35 static const UChar OPEN_REV = 0x0028; // ( |
34 static const UChar CLOSE_REV = 0x0029; // ) | 36 static const UChar CLOSE_REV = 0x0029; // ) |
35 | 37 |
36 //static const UChar EMPTY[] = {0}; // "" | 38 //static const UChar EMPTY[] = {0}; // "" |
37 static const UChar ANY[] = {65,110,121,0}; // "Any" | 39 static const UChar ANY[] = {65,110,121,0}; // "Any" |
38 static const UChar ANY_NULL[] = {65,110,121,45,78,117,108,108,0}; // "Any-Null" | 40 static const UChar ANY_NULL[] = {65,110,121,45,78,117,108,108,0}; // "Any-Null" |
39 | 41 |
40 static const int32_t FORWARD = UTRANS_FORWARD; | 42 static const int32_t FORWARD = UTRANS_FORWARD; |
41 static const int32_t REVERSE = UTRANS_REVERSE; | 43 static const int32_t REVERSE = UTRANS_REVERSE; |
42 | 44 |
43 static Hashtable* SPECIAL_INVERSES = NULL; | 45 static Hashtable* SPECIAL_INVERSES = NULL; |
| 46 static UInitOnce gSpecialInversesInitOnce = U_INITONCE_INITIALIZER; |
44 | 47 |
45 /** | 48 /** |
46 * The mutex controlling access to SPECIAL_INVERSES | 49 * The mutex controlling access to SPECIAL_INVERSES |
47 */ | 50 */ |
48 static UMutex LOCK = U_MUTEX_INITIALIZER; | 51 static UMutex LOCK = U_MUTEX_INITIALIZER; |
49 | 52 |
50 TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString
& t, | 53 TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString
& t, |
51 const UnicodeString& v, UBool sawS, | 54 const UnicodeString& v, UBool sawS, |
52 const UnicodeString& f) { | 55 const UnicodeString& f) { |
53 source = s; | 56 source = s; |
(...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
637 * @param target the target against which to register the inverse | 640 * @param target the target against which to register the inverse |
638 * @param inverseTarget the inverse of target, that is | 641 * @param inverseTarget the inverse of target, that is |
639 * Any-target.getInverse() => Any-inverseTarget | 642 * Any-target.getInverse() => Any-inverseTarget |
640 * @param bidirectional if TRUE, register the reverse relation | 643 * @param bidirectional if TRUE, register the reverse relation |
641 * as well, that is, Any-inverseTarget.getInverse() => Any-target | 644 * as well, that is, Any-inverseTarget.getInverse() => Any-target |
642 */ | 645 */ |
643 void TransliteratorIDParser::registerSpecialInverse(const UnicodeString& target, | 646 void TransliteratorIDParser::registerSpecialInverse(const UnicodeString& target, |
644 const UnicodeString& inverse
Target, | 647 const UnicodeString& inverse
Target, |
645 UBool bidirectional, | 648 UBool bidirectional, |
646 UErrorCode &status) { | 649 UErrorCode &status) { |
647 init(status); | 650 umtx_initOnce(gSpecialInversesInitOnce, init, status); |
648 if (U_FAILURE(status)) { | 651 if (U_FAILURE(status)) { |
649 return; | 652 return; |
650 } | 653 } |
651 | 654 |
652 // If target == inverseTarget then force bidirectional => FALSE | 655 // If target == inverseTarget then force bidirectional => FALSE |
653 if (bidirectional && 0==target.caseCompare(inverseTarget, U_FOLD_CASE_DEFAUL
T)) { | 656 if (bidirectional && 0==target.caseCompare(inverseTarget, U_FOLD_CASE_DEFAUL
T)) { |
654 bidirectional = FALSE; | 657 bidirectional = FALSE; |
655 } | 658 } |
656 | 659 |
657 Mutex lock(&LOCK); | 660 Mutex lock(&LOCK); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 * special inverse of that ID. If there is no special inverse | 847 * special inverse of that ID. If there is no special inverse |
845 * then return NULL. | 848 * then return NULL. |
846 * @return a SingleID or NULL. Returned object always has | 849 * @return a SingleID or NULL. Returned object always has |
847 * 'filter' field of NULL. | 850 * 'filter' field of NULL. |
848 */ | 851 */ |
849 TransliteratorIDParser::SingleID* | 852 TransliteratorIDParser::SingleID* |
850 TransliteratorIDParser::specsToSpecialInverse(const Specs& specs, UErrorCode &st
atus) { | 853 TransliteratorIDParser::specsToSpecialInverse(const Specs& specs, UErrorCode &st
atus) { |
851 if (0!=specs.source.caseCompare(ANY, 3, U_FOLD_CASE_DEFAULT)) { | 854 if (0!=specs.source.caseCompare(ANY, 3, U_FOLD_CASE_DEFAULT)) { |
852 return NULL; | 855 return NULL; |
853 } | 856 } |
854 init(status); | 857 umtx_initOnce(gSpecialInversesInitOnce, init, status); |
| 858 if (U_FAILURE(status)) { |
| 859 return NULL; |
| 860 } |
855 | 861 |
856 UnicodeString* inverseTarget; | 862 UnicodeString* inverseTarget; |
857 | 863 |
858 umtx_lock(&LOCK); | 864 umtx_lock(&LOCK); |
859 inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target); | 865 inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target); |
860 umtx_unlock(&LOCK); | 866 umtx_unlock(&LOCK); |
861 | 867 |
862 if (inverseTarget != NULL) { | 868 if (inverseTarget != NULL) { |
863 // If the original ID contained "Any-" then make the | 869 // If the original ID contained "Any-" then make the |
864 // special inverse "Any-Foo"; otherwise make it "Foo". | 870 // special inverse "Any-Foo"; otherwise make it "Foo". |
(...skipping 22 matching lines...) Expand all Loading... |
887 /** | 893 /** |
888 * Glue method to get around access problems in C++. This would | 894 * Glue method to get around access problems in C++. This would |
889 * ideally be inline but we want to avoid a circular header | 895 * ideally be inline but we want to avoid a circular header |
890 * dependency. | 896 * dependency. |
891 */ | 897 */ |
892 Transliterator* TransliteratorIDParser::createBasicInstance(const UnicodeString&
id, const UnicodeString* canonID) { | 898 Transliterator* TransliteratorIDParser::createBasicInstance(const UnicodeString&
id, const UnicodeString* canonID) { |
893 return Transliterator::createBasicInstance(id, canonID); | 899 return Transliterator::createBasicInstance(id, canonID); |
894 } | 900 } |
895 | 901 |
896 /** | 902 /** |
897 * Initialize static memory. | 903 * Initialize static memory. Called through umtx_initOnce only. |
898 */ | 904 */ |
899 void TransliteratorIDParser::init(UErrorCode &status) { | 905 void TransliteratorIDParser::init(UErrorCode &status) { |
900 if (SPECIAL_INVERSES != NULL) { | 906 U_ASSERT(SPECIAL_INVERSES == NULL); |
901 return; | 907 ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, utrans_transliterator_cl
eanup); |
902 } | |
903 | 908 |
904 Hashtable* special_inverses = new Hashtable(TRUE, status); | 909 SPECIAL_INVERSES = new Hashtable(TRUE, status); |
905 // Null pointer check | 910 if (SPECIAL_INVERSES == NULL) { |
906 if (special_inverses == NULL) { | |
907 status = U_MEMORY_ALLOCATION_ERROR; | 911 status = U_MEMORY_ALLOCATION_ERROR; |
908 return; | 912 return; |
909 } | 913 } |
910 special_inverses->setValueDeleter(uprv_deleteUObject); | 914 SPECIAL_INVERSES->setValueDeleter(uprv_deleteUObject); |
911 | |
912 umtx_lock(&LOCK); | |
913 if (SPECIAL_INVERSES == NULL) { | |
914 SPECIAL_INVERSES = special_inverses; | |
915 special_inverses = NULL; | |
916 } | |
917 umtx_unlock(&LOCK); | |
918 delete special_inverses; /*null instance*/ | |
919 | |
920 ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, utrans_transliterator_cl
eanup); | |
921 } | 915 } |
922 | 916 |
923 /** | 917 /** |
924 * Free static memory. | 918 * Free static memory. |
925 */ | 919 */ |
926 void TransliteratorIDParser::cleanup() { | 920 void TransliteratorIDParser::cleanup() { |
927 if (SPECIAL_INVERSES) { | 921 if (SPECIAL_INVERSES) { |
928 delete SPECIAL_INVERSES; | 922 delete SPECIAL_INVERSES; |
929 SPECIAL_INVERSES = NULL; | 923 SPECIAL_INVERSES = NULL; |
930 } | 924 } |
| 925 gSpecialInversesInitOnce.reset(); |
931 } | 926 } |
932 | 927 |
933 U_NAMESPACE_END | 928 U_NAMESPACE_END |
934 | 929 |
935 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ | 930 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ |
936 | 931 |
937 //eof | 932 //eof |
OLD | NEW |