ICU-4143 avoid mutexes in UCharacter.tolower() and similar; load case/bidi properties in UCharacter.static{} (as in 3.0) and use dummy objects when data is not available

X-SVN-Rev: 17252
This commit is contained in:
Markus Scherer 2005-02-24 23:51:34 +00:00
parent 5d90e8e4c9
commit 360a8cf2f1
8 changed files with 296 additions and 97 deletions

View File

@ -7,6 +7,9 @@
package com.ibm.icu.dev.test.lang;
import com.ibm.icu.impl.UBiDiProps;
import com.ibm.icu.impl.UCaseProps;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.dev.test.TestUtil;
import com.ibm.icu.lang.UCharacter;
@ -2306,4 +2309,17 @@ public final class UCharacterTest extends TestFmwk
assertEquals("UCharacter.forDigit ", "h", String.valueOf(ch2));
}
public void TestCasePropsDummy() {
// code coverage for UCaseProps.getDummy()
if(UCaseProps.getDummy().tolower(0x41)!=0x41) {
errln("UCaseProps.getDummy().tolower(0x41)!=0x41");
}
}
public void TestBiDiPropsDummy() {
// code coverage for UBiDiProps.getDummy()
if(UBiDiProps.getDummy().getClass(0x20)!=0) {
errln("UBiDiProps.getDummy().getClass(0x20)!=0");
}
}
}

View File

@ -1,6 +1,6 @@
/**
*******************************************************************************
* Copyright (C) 1996-2004, International Business Machines Corporation and *
* Copyright (C) 1996-2005, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -515,5 +515,58 @@ public final class TrieTest extends TestFmwk
}
}
}
}
private static class DummyGetFoldingOffset implements Trie.DataManipulate {
public int getFoldingOffset(int value) {
return -1; /* never get non-initialValue data for supplementary code points */
}
}
public void TestDummyCharTrie() {
CharTrie trie;
final int initialValue=0x313, leadUnitValue=0xaffe;
int value;
int c;
trie=new CharTrie(initialValue, leadUnitValue, new DummyGetFoldingOffset());
/* test that all code points have initialValue */
for(c=0; c<=0x10ffff; ++c) {
value=trie.getCodePointValue(c);
if(value!=initialValue) {
errln("CharTrie/dummy.getCodePointValue(c)(U+"+hex(c)+")=0x"+hex(value)+" instead of 0x"+hex(initialValue));
}
}
/* test that the lead surrogate code units have leadUnitValue */
for(c=0xd800; c<=0xdbff; ++c) {
value=trie.getLeadValue((char)c);
if(value!=leadUnitValue) {
errln("CharTrie/dummy.getLeadValue(c)(U+"+hex(c)+")=0x"+hex(value)+" instead of 0x"+hex(leadUnitValue));
}
}
}
public void TestDummyIntTrie() {
IntTrie trie;
final int initialValue=0x01234567, leadUnitValue=0x89abcdef;
int value;
int c;
trie=new IntTrie(initialValue, leadUnitValue, new DummyGetFoldingOffset());
/* test that all code points have initialValue */
for(c=0; c<=0x10ffff; ++c) {
value=trie.getCodePointValue(c);
if(value!=initialValue) {
errln("IntTrie/dummy.getCodePointValue(c)(U+"+hex(c)+")=0x"+hex(value)+" instead of 0x"+hex(initialValue));
}
}
/* test that the lead surrogate code units have leadUnitValue */
for(c=0xd800; c<=0xdbff; ++c) {
value=trie.getLeadValue((char)c);
if(value!=leadUnitValue) {
errln("IntTrie/dummy.getLeadValue(c)(U+"+hex(c)+")=0x"+hex(value)+" instead of 0x"+hex(leadUnitValue));
}
}
}
}

View File

@ -48,7 +48,67 @@ public class CharTrie extends Trie
}
m_friendAgent_ = new FriendAgent();
}
/**
* Make a dummy CharTrie.
* A dummy trie is an empty runtime trie, used when a real data trie cannot
* be loaded.
*
* The trie always returns the initialValue,
* or the leadUnitValue for lead surrogate code points.
* The Latin-1 part is always set up to be linear.
*
* @param initialValue the initial value that is set for all code points
* @param leadUnitValue the value for lead surrogate code _units_ that do not
* have associated supplementary data
* @param dataManipulate object which provides methods to parse the char data
*/
public CharTrie(int initialValue, int leadUnitValue, DataManipulate dataManipulate) {
super(new char[BMP_INDEX_LENGTH+SURROGATE_BLOCK_COUNT], HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_, dataManipulate);
int dataLength, latin1Length, i, limit;
char block;
/* calculate the actual size of the dummy trie data */
/* max(Latin-1, block 0) */
dataLength=latin1Length= INDEX_STAGE_1_SHIFT_<=8 ? 256 : DATA_BLOCK_LENGTH;
if(leadUnitValue!=initialValue) {
dataLength+=DATA_BLOCK_LENGTH;
}
m_data_=new char[dataLength];
m_dataLength_=dataLength;
m_initialValue_=(char)initialValue;
/* fill the index and data arrays */
/* indexes are preset to 0 (block 0) */
/* Latin-1 data */
for(i=0; i<latin1Length; ++i) {
m_data_[i]=(char)initialValue;
}
if(leadUnitValue!=initialValue) {
/* indexes for lead surrogate code units to the block after Latin-1 */
block=(char)(latin1Length>>INDEX_STAGE_2_SHIFT_);
i=0xd800>>INDEX_STAGE_1_SHIFT_;
limit=0xdc00>>INDEX_STAGE_1_SHIFT_;
for(; i<limit; ++i) {
m_index_[i]=block;
}
/* data for lead surrogate code units */
limit=latin1Length+DATA_BLOCK_LENGTH;
for(i=latin1Length; i<limit; ++i) {
m_data_[i]=(char)leadUnitValue;
}
}
m_friendAgent_ = new FriendAgent();
}
/**
* Java friend implementation
*/

View File

@ -44,6 +44,64 @@ public class IntTrie extends Trie
}
}
/**
* Make a dummy IntTrie.
* A dummy trie is an empty runtime trie, used when a real data trie cannot
* be loaded.
*
* The trie always returns the initialValue,
* or the leadUnitValue for lead surrogate code points.
* The Latin-1 part is always set up to be linear.
*
* @param initialValue the initial value that is set for all code points
* @param leadUnitValue the value for lead surrogate code _units_ that do not
* have associated supplementary data
* @param dataManipulate object which provides methods to parse the char data
*/
public IntTrie(int initialValue, int leadUnitValue, DataManipulate dataManipulate) {
super(new char[BMP_INDEX_LENGTH+SURROGATE_BLOCK_COUNT], HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_, dataManipulate);
int dataLength, latin1Length, i, limit;
char block;
/* calculate the actual size of the dummy trie data */
/* max(Latin-1, block 0) */
dataLength=latin1Length= INDEX_STAGE_1_SHIFT_<=8 ? 256 : DATA_BLOCK_LENGTH;
if(leadUnitValue!=initialValue) {
dataLength+=DATA_BLOCK_LENGTH;
}
m_data_=new int[dataLength];
m_dataLength_=dataLength;
m_initialValue_=initialValue;
/* fill the index and data arrays */
/* indexes are preset to 0 (block 0) */
/* Latin-1 data */
for(i=0; i<latin1Length; ++i) {
m_data_[i]=initialValue;
}
if(leadUnitValue!=initialValue) {
/* indexes for lead surrogate code units to the block after Latin-1 */
block=(char)(latin1Length>>INDEX_STAGE_2_SHIFT_);
i=0xd800>>INDEX_STAGE_1_SHIFT_;
limit=0xdc00>>INDEX_STAGE_1_SHIFT_;
for(; i<limit; ++i) {
m_index_[i]=block;
}
/* data for lead surrogate code units */
limit=latin1Length+DATA_BLOCK_LENGTH;
for(i=latin1Length; i<limit; ++i) {
m_data_[i]=leadUnitValue;
}
}
}
// public methods --------------------------------------------------
/**

View File

@ -213,13 +213,26 @@ public abstract class Trie
* @draft 2.1
*/
protected static final int INDEX_STAGE_2_SHIFT_ = 2;
/**
* Number of data values in a stage 2 (data array) block.
*/
protected static final int DATA_BLOCK_LENGTH=1<<INDEX_STAGE_1_SHIFT_;
/**
* Mask for getting the lower bits from the input index.
* DATA_BLOCK_LENGTH_ - 1.
* DATA_BLOCK_LENGTH - 1.
* @draft 2.1
*/
protected static final int INDEX_STAGE_3_MASK_ =
(1 << INDEX_STAGE_1_SHIFT_) - 1;
protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1;
/** Number of bits of a trail surrogate that are used in index table lookups. */
protected static final int SURROGATE_BLOCK_BITS=10-INDEX_STAGE_1_SHIFT_;
/**
* Number of index (stage 1) entries per lead surrogate.
* Same as number of index entries for 1024 trail surrogates,
* ==0x400>>INDEX_STAGE_1_SHIFT_
*/
protected static final int SURROGATE_BLOCK_COUNT=(1<<SURROGATE_BLOCK_BITS);
/** Length of the BMP portion of the index (stage 1) array. */
protected static final int BMP_INDEX_LENGTH=0x10000>>INDEX_STAGE_1_SHIFT_;
/**
* Surrogate mask to use when shifting offset to retrieve supplementary
* values
@ -421,7 +434,7 @@ public abstract class Trie
/**
* Latin 1 option mask
*/
private static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200;
protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200;
/**
* Constant number to authenticate the byte block
*/
@ -431,7 +444,7 @@ public abstract class Trie
*/
private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF;
private static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4;
private static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100;
protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100;
/**
* Flag indicator for Latin quick access data block

View File

@ -103,6 +103,30 @@ public final class UBiDiProps {
return gBdp;
}
// UBiDiProps dummy singleton
private static UBiDiProps gBdpDummy=null;
private UBiDiProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature
formatVersion=new byte[] { 1, 0, Trie.INDEX_STAGE_1_SHIFT_, Trie.INDEX_STAGE_2_SHIFT_ };
unicodeVersion=new byte[] { 2, 0, 0, 0 };
indexes=new int[IX_TOP];
indexes[0]=IX_TOP;
trie=new CharTrie(0, 0, null); // dummy trie, always returns 0
}
/**
* Get a singleton dummy object, one that works with no real data.
* This can be used when the real data is not available.
* Using the dummy can reduce checks for available data after an initial failure.
* Port of ucase_getDummy().
*/
public static final synchronized UBiDiProps getDummy() {
if(gBdpDummy==null) {
gBdpDummy=new UBiDiProps(true);
}
return gBdpDummy;
}
// set of property starts for UnicodeSet ------------------------------- ***
public final void addPropertyStarts(UnicodeSet set) {

View File

@ -46,7 +46,7 @@ public final class UCaseProps {
is.close();
}
private void readData(InputStream is) throws IOException {
private final void readData(InputStream is) throws IOException {
DataInputStream inputStream=new DataInputStream(is);
// read the header
@ -107,6 +107,30 @@ public final class UCaseProps {
return gCsp;
}
// UCaseProps dummy singleton
private static UCaseProps gCspDummy=null;
private UCaseProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature
formatVersion=new byte[] { 1, 0, Trie.INDEX_STAGE_1_SHIFT_, Trie.INDEX_STAGE_2_SHIFT_ };
unicodeVersion=new byte[] { 2, 0, 0, 0 };
indexes=new int[IX_TOP];
indexes[0]=IX_TOP;
trie=new CharTrie(0, 0, null); // dummy trie, always returns 0
}
/**
* Get a singleton dummy object, one that works with no real data.
* This can be used when the real data is not available.
* Using the dummy can reduce checks for available data after an initial failure.
* Port of ucase_getDummy().
*/
public static final synchronized UCaseProps getDummy() {
if(gCspDummy==null) {
gCspDummy=new UCaseProps(true);
}
return gCspDummy;
}
// set of property starts for UnicodeSet ------------------------------- ***
public final void addPropertyStarts(UnicodeSet set) {

View File

@ -3200,11 +3200,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @stable ICU 2.1
*/
public static int toLowerCase(int ch) {
try {
return UCaseProps.getSingleton().tolower(ch);
} catch(IOException e) {
}
return ch;
return gCsp.tolower(ch);
}
/**
@ -3254,11 +3250,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @stable ICU 2.1
*/
public static int toTitleCase(int ch) {
try {
return UCaseProps.getSingleton().totitle(ch);
} catch(IOException e) {
}
return ch;
return gCsp.totitle(ch);
}
/**
@ -3276,11 +3268,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @stable ICU 2.1
*/
public static int toUpperCase(int ch) {
try {
return UCaseProps.getSingleton().toupper(ch);
} catch(IOException e) {
}
return ch;
return gCsp.toupper(ch);
}
// extra methods not in java.lang.Character --------------------------
@ -3368,11 +3356,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
*/
public static int getDirection(int ch)
{
try {
return UBiDiProps.getSingleton().getClass(ch);
} catch (IOException e) {
}
return UCharacterEnums.ECharacterDirection.LEFT_TO_RIGHT;
return gBdp.getClass(ch);
}
/**
@ -3386,11 +3370,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
*/
public static boolean isMirrored(int ch)
{
try {
return UBiDiProps.getSingleton().isMirrored(ch);
} catch (IOException e) {
}
return false;
return gBdp.isMirrored(ch);
}
/**
@ -3409,11 +3389,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
*/
public static int getMirror(int ch)
{
try {
return UBiDiProps.getSingleton().getMirror(ch);
} catch (IOException e) {
}
return ch;
return gBdp.getMirror(ch);
}
/**
@ -4051,13 +4027,6 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @deprecated This is a draft API and might change in a future release of ICU.
*/
public static String toUpperCase(ULocale locale, String str) {
UCaseProps csp;
try {
csp=UCaseProps.getSingleton();
} catch (IOException e) {
return str;
}
StringContextIterator iter = new StringContextIterator(str);
StringBuffer result = new StringBuffer(str.length());
int[] locCache = new int[1];
@ -4069,7 +4038,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
locCache[0]=0;
while((c=iter.nextCaseMapCP())>=0) {
c=csp.toFullUpper(c, iter, result, locale, locCache);
c=gCsp.toFullUpper(c, iter, result, locale, locCache);
/* decode the result */
if(c<0) {
@ -4112,13 +4081,6 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @deprecated This is a draft API and might change in a future release of ICU.
*/
public static String toLowerCase(ULocale locale, String str) {
UCaseProps csp;
try {
csp=UCaseProps.getSingleton();
} catch (IOException e) {
return str;
}
StringContextIterator iter = new StringContextIterator(str);
StringBuffer result = new StringBuffer(str.length());
int[] locCache = new int[1];
@ -4130,7 +4092,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
locCache[0]=0;
while((c=iter.nextCaseMapCP())>=0) {
c=csp.toFullLower(c, iter, result, locale, locCache);
c=gCsp.toFullLower(c, iter, result, locale, locCache);
/* decode the result */
if(c<0) {
@ -4197,13 +4159,6 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
*/
public static String toTitleCase(ULocale locale, String str,
BreakIterator titleIter) {
UCaseProps csp;
try {
csp=UCaseProps.getSingleton();
} catch (IOException e) {
return str;
}
StringContextIterator iter = new StringContextIterator(str);
StringBuffer result = new StringBuffer(str.length());
int[] locCache = new int[1];
@ -4241,7 +4196,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
/* lowercase up to index */
iter.setLimit(index);
while((c=iter.nextCaseMapCP())>=0) {
c=csp.toFullLower(c, iter, result, locale, locCache);
c=gCsp.toFullLower(c, iter, result, locale, locCache);
/* decode the result */
if(c<0) {
@ -4269,7 +4224,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
if(c<0) {
break; // reached end of str
}
c=csp.toFullTitle(c, iter, result, locale, locCache);
c=gCsp.toFullTitle(c, iter, result, locale, locCache);
/* decode the result */
if(c<0) {
@ -4359,11 +4314,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @stable ICU 2.6
*/
public static int foldCase(int ch, int options) {
try {
return UCaseProps.getSingleton().fold(ch, options);
} catch (IOException e) {
}
return ch;
return gCsp.fold(ch, options);
}
/**
@ -4382,13 +4333,6 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
* @stable ICU 2.6
*/
public static final String foldCase(String str, int options) {
UCaseProps csp;
try {
csp=UCaseProps.getSingleton();
} catch (IOException e) {
return str;
}
StringBuffer result = new StringBuffer(str.length());
int c, i, length;
@ -4396,7 +4340,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
for(i=0; i<length;) {
c=UTF16.charAt(str, i);
i+=UTF16.getCharCount(c);
c=csp.toFullFolding(c, result, options);
c=gCsp.toFullFolding(c, result, options);
/* decode the result */
if(c<0) {
@ -4759,17 +4703,9 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
case UProperty.GENERAL_CATEGORY:
return getType(ch);
case UProperty.JOINING_GROUP:
try {
return UBiDiProps.getSingleton().getJoiningGroup(ch);
} catch (IOException e) {
}
return 0;
return gBdp.getJoiningGroup(ch);
case UProperty.JOINING_TYPE:
try {
return UBiDiProps.getSingleton().getJoiningType(ch);
} catch (IOException e) {
}
return 0;
return gBdp.getJoiningType(ch);
case UProperty.LINE_BREAK:
return (int)(PROPERTY_.getAdditional(ch, 0)& LINE_BREAK_MASK_)>>LINE_BREAK_SHIFT_;
case UProperty.NUMERIC_TYPE:
@ -4938,11 +4874,7 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
case UProperty.BIDI_CLASS:
case UProperty.JOINING_GROUP:
case UProperty.JOINING_TYPE:
try {
return UBiDiProps.getSingleton().getMaxValue(type);
} catch (IOException e) {
}
return 0;
return gBdp.getMaxValue(type);
case UProperty.BLOCK:
return (PROPERTY_.getMaxValues(0) & BLOCK_MASK_) >> BLOCK_SHIFT_;
case UProperty.CANONICAL_COMBINING_CLASS:
@ -5572,20 +5504,39 @@ public final class UCharacter implements ECharacterCategory, ECharacterDirection
private static final char[] PROPERTY_TRIE_DATA_;
private static final int PROPERTY_INITIAL_VALUE_;
private static final UCaseProps gCsp;
private static final UBiDiProps gBdp;
// block to initialise character property database
static
{
try
{
PROPERTY_ = UCharacterProperty.getInstance();
PROPERTY_TRIE_INDEX_ = PROPERTY_.m_trieIndex_;
PROPERTY_TRIE_DATA_ = PROPERTY_.m_trieData_;
PROPERTY_INITIAL_VALUE_ = PROPERTY_.m_trieInitialValue_;
PROPERTY_ = UCharacterProperty.getInstance();
PROPERTY_TRIE_INDEX_ = PROPERTY_.m_trieIndex_;
PROPERTY_TRIE_DATA_ = PROPERTY_.m_trieData_;
PROPERTY_INITIAL_VALUE_ = PROPERTY_.m_trieInitialValue_;
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage());
throw new RuntimeException(e.getMessage());
}
UCaseProps csp;
try {
csp=UCaseProps.getSingleton();
} catch(IOException e) {
csp=UCaseProps.getDummy();
}
gCsp=csp;
UBiDiProps bdp;
try {
bdp=UBiDiProps.getSingleton();
} catch(IOException e) {
bdp=UBiDiProps.getDummy();
}
gBdp=bdp;
}
/**