com.ibm.icu.impl.Trie2Writable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icu4j Show documentation
Show all versions of icu4j Show documentation
International Component for Unicode for Java (ICU4J) is a mature, widely used Java library
providing Unicode and Globalization support
/*
*******************************************************************************
* Copyright (C) 2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.impl;
/**
* @author aheninger
*
* A Trie2Writable is a modifiable, or build-time Trie2.
* Functions for reading data from the Trie are all from class Trie2.
*
*/
public class Trie2Writable extends Trie2 {
/**
* Create a new, empty, writable Trie2. 32-bit data values are used.
*
* @param initialValueP the initial value that is set for all code points
* @param errorValueP the value for out-of-range code points and illegal UTF-8
*/
public Trie2Writable(int initialValueP, int errorValueP) {
// This constructor corresponds to utrie2_open() in ICU4C.
init(initialValueP, errorValueP);
}
private void init(int initialValueP, int errorValueP) {
this.initialValue = initialValueP;
this.errorValue = errorValueP;
this.highStart = 0x110000;
this.data = new int[UNEWTRIE2_INITIAL_DATA_LENGTH];
this.dataCapacity = UNEWTRIE2_INITIAL_DATA_LENGTH;
this.initialValue = initialValueP;
this.errorValue = errorValueP;
this.highStart = 0x110000;
this.firstFreeBlock = 0; /* no free block in the list */
this.isCompacted = false;
/*
* preallocate and reset
* - ASCII
* - the bad-UTF-8-data block
* - the null data block
*/
int i, j;
for(i=0; i<0x80; ++i) {
data[i] = initialValue;
}
for(; i<0xc0; ++i) {
data[i] = errorValue;
}
for(i=UNEWTRIE2_DATA_NULL_OFFSET; i>UTRIE2_SHIFT_2 ASCII data blocks */
for(i=0, j=0; j<0x80; ++i, j+=UTRIE2_DATA_BLOCK_LENGTH) {
index2[i]=j;
map[i]=1;
}
/* reference counts for the bad-UTF-8-data block */
for(; j<0xc0; ++i, j+=UTRIE2_DATA_BLOCK_LENGTH) {
map[i]=0;
}
/*
* Reference counts for the null data block: all blocks except for the ASCII blocks.
* Plus 1 so that we don't drop this block during compaction.
* Plus as many as needed for lead surrogate code points.
*/
/* i==newTrie->dataNullOffset */
map[i++] =
(0x110000>>UTRIE2_SHIFT_2) -
(0x80>>UTRIE2_SHIFT_2) +
1 +
UTRIE2_LSCP_INDEX_2_LENGTH;
j += UTRIE2_DATA_BLOCK_LENGTH;
for(; j>UTRIE2_SHIFT_2; i>UTRIE2_SHIFT_2))+
(c>>UTRIE2_SHIFT_2);
} else {
i2=index1[c>>UTRIE2_SHIFT_1]+
((c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK);
}
block=index2[i2];
return (block==dataNullOffset);
}
private int allocIndex2Block() {
int newBlock, newTop;
newBlock=index2Length;
newTop=newBlock+UTRIE2_INDEX_2_BLOCK_LENGTH;
if(newTop > index2.length) {
throw new IllegalStateException("Internal error in Trie2 creation.");
/*
* Should never occur.
* Either UTRIE2_MAX_BUILD_TIME_INDEX_LENGTH is incorrect,
* or the code writes more values than should be possible.
*/
}
index2Length=newTop;
System.arraycopy(index2, index2NullOffset, index2, newBlock, UTRIE2_INDEX_2_BLOCK_LENGTH);
return newBlock;
}
private int getIndex2Block(int c, boolean forLSCP) {
int i1, i2;
if(c>=0xd800 && c<0xdc00 && forLSCP) {
return UTRIE2_LSCP_INDEX_2_OFFSET;
}
i1=c>>UTRIE2_SHIFT_1;
i2=index1[i1];
if(i2==index2NullOffset) {
i2=allocIndex2Block();
index1[i1]=i2;
}
return i2;
}
private int allocDataBlock(int copyBlock) {
int newBlock, newTop;
if(firstFreeBlock!=0) {
/* get the first free block */
newBlock=firstFreeBlock;
firstFreeBlock=-map[newBlock>>UTRIE2_SHIFT_2];
} else {
/* get a new block from the high end */
newBlock=dataLength;
newTop=newBlock+UTRIE2_DATA_BLOCK_LENGTH;
if(newTop>dataCapacity) {
/* out of memory in the data array */
int capacity;
int[] newData;
if(dataCapacity>UTRIE2_SHIFT_2]=0;
return newBlock;
}
/* call when the block's reference counter reaches 0 */
private void releaseDataBlock(int block) {
/* put this block at the front of the free-block chain */
map[block>>UTRIE2_SHIFT_2]=-firstFreeBlock;
firstFreeBlock=block;
}
private boolean isWritableBlock(int block) {
return (block!=dataNullOffset && 1==map[block>>UTRIE2_SHIFT_2]);
}
private void setIndex2Entry(int i2, int block) {
int oldBlock;
++map[block>>UTRIE2_SHIFT_2]; /* increment first, in case block==oldBlock! */
oldBlock=index2[i2];
if(0 == --map[oldBlock>>UTRIE2_SHIFT_2]) {
releaseDataBlock(oldBlock);
}
index2[i2]=block;
}
/**
* No error checking for illegal arguments.
*
* @internal
*/
private int getDataBlock(int c, boolean forLSCP) {
int i2, oldBlock, newBlock;
i2=getIndex2Block(c, forLSCP);
i2+=(c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
oldBlock=index2[i2];
if(isWritableBlock(oldBlock)) {
return oldBlock;
}
/* allocate a new data block */
newBlock=allocDataBlock(oldBlock);
setIndex2Entry(i2, newBlock);
return newBlock;
}
/**
* Set a value for a code point.
*
* @param c the code point
* @param value the value
*/
public Trie2Writable set(int c, int value) {
if (c<0 || c>0x10ffff) {
throw new IllegalArgumentException("Invalid code point.");
}
set(c, true, value);
fHash = 0;
return this;
}
private Trie2Writable set(int c, boolean forLSCP, int value) {
int block;
if (isCompacted) {
uncompact();
}
block = getDataBlock(c, forLSCP);
data[block + (c&UTRIE2_DATA_MASK)] = value;
return this;
}
/*
* Uncompact a compacted Trie2Writable.
* This is needed if a the WritableTrie2 was compacted in preparation for creating a read-only
* Trie2, and then is subsequently altered.
*
* The structure is a bit awkward - it would be cleaner to leave the original
* Trie2 unaltered - but compacting in place was taken directly from the ICU4C code.
*
* The approach is to create a new (uncompacted) Trie2Writable from this one, then transfer
* the guts from the new to the old.
*/
private void uncompact() {
Trie2Writable tempTrie = new Trie2Writable(this);
// Members from Trie2Writable
this.index1 = tempTrie.index1;
this.index2 = tempTrie.index2;
this.data = tempTrie.data;
this.index2Length = tempTrie.index2Length;
this.dataCapacity = tempTrie.dataCapacity;
this.isCompacted = tempTrie.isCompacted;
// Members From Trie2
this.header = tempTrie.header;
this.index = tempTrie.index;
this.data16 = tempTrie.data16;
this.data32 = tempTrie.data32;
this.indexLength = tempTrie.indexLength;
this.dataLength = tempTrie.dataLength;
this.index2NullOffset = tempTrie.index2NullOffset;
this.initialValue = tempTrie.initialValue;
this.errorValue = tempTrie.errorValue;
this.highStart = tempTrie.highStart;
this.highValueIndex = tempTrie.highValueIndex;
this.dataNullOffset = tempTrie.dataNullOffset;
}
private void writeBlock(int block, int value) {
int limit=block+UTRIE2_DATA_BLOCK_LENGTH;
while(block0x10ffff || start<0 || end>0x10ffff || end<0 || start>end) {
throw new IllegalArgumentException("Invalid code point range.");
}
if(!overwrite && value==initialValue) {
return this; /* nothing to do */
}
fHash = 0;
if(isCompacted) {
this.uncompact();
}
limit=end+1;
if((start&UTRIE2_DATA_MASK) != 0) {
int /*UChar32*/ nextStart;
/* set partial block at [start..following block boundary[ */
block=getDataBlock(start, true);
nextStart=(start+UTRIE2_DATA_BLOCK_LENGTH)&~UTRIE2_DATA_MASK;
if(nextStart<=limit) {
fillBlock(block, start&UTRIE2_DATA_MASK, UTRIE2_DATA_BLOCK_LENGTH,
value, initialValue, overwrite);
start=nextStart;
} else {
fillBlock(block, start&UTRIE2_DATA_MASK, limit&UTRIE2_DATA_MASK,
value, initialValue, overwrite);
return this;
}
}
/* number of positions in the last, partial block */
rest=limit&UTRIE2_DATA_MASK;
/* round down limit to a block boundary */
limit&=~UTRIE2_DATA_MASK;
/* iterate over all-value blocks */
if(value==initialValue) {
repeatBlock=dataNullOffset;
} else {
repeatBlock=-1;
}
while(start>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
block=index2[i2];
if(isWritableBlock(block)) {
/* already allocated */
if(overwrite && block>=UNEWTRIE2_DATA_0800_OFFSET) {
/*
* We overwrite all values, and it's not a
* protected (ASCII-linear or 2-byte UTF-8) block:
* replace with the repeatBlock.
*/
setRepeatBlock=true;
} else {
/* !overwrite, or protected block: just write the values into this block */
fillBlock(block,
0, UTRIE2_DATA_BLOCK_LENGTH,
value, initialValue, overwrite);
}
} else if(data[block]!=value && (overwrite || block==dataNullOffset)) {
/*
* Set the repeatBlock instead of the null block or previous repeat block:
*
* If !isWritableBlock() then all entries in the block have the same value
* because it's the null block or a range block (the repeatBlock from a previous
* call to utrie2_setRange32()).
* No other blocks are used multiple times before compacting.
*
* The null block is the only non-writable block with the initialValue because
* of the repeatBlock initialization above. (If value==initialValue, then
* the repeatBlock will be the null data block.)
*
* We set our repeatBlock if the desired value differs from the block's value,
* and if we overwrite any data or if the data is all initial values
* (which is the same as the block being the null block, see above).
*/
setRepeatBlock=true;
}
if(setRepeatBlock) {
if(repeatBlock>=0) {
setIndex2Entry(i2, repeatBlock);
} else {
/* create and set and fill the repeatBlock */
repeatBlock=getDataBlock(start, true);
writeBlock(repeatBlock, value);
}
}
start+=UTRIE2_DATA_BLOCK_LENGTH;
}
if(rest>0) {
/* set partial block at [last block boundary..limit[ */
block=getDataBlock(start, true);
fillBlock(block, 0, rest, value, initialValue, overwrite);
}
return this;
}
/**
* Set the values from a Trie2.Range.
*
* All code points within the range will get the value if
* overwrite is TRUE or if the old value is the initial value.
*
* Ranges with the lead surrogate flag set will set the alternate
* lead-surrogate values in the Trie, rather than the code point values.
*
* This function is intended to work with the ranges produced when iterating
* the contents of a source Trie.
*
* @param range contains the range of code points and the value to be set.
* @param overwrite flag for whether old non-initial values are to be overwritten
*/
public Trie2Writable setRange(Trie2.Range range, boolean overwrite) {
fHash = 0;
if (range.leadSurrogate) {
for (int c=range.startCodePoint; c<=range.endCodePoint; c++) {
if (overwrite || getFromU16SingleLead((char)c) == this.initialValue) {
setForLeadSurrogateCodeUnit((char)c, range.value);
}
}
} else {
setRange(range.startCodePoint, range.endCodePoint, range.value, overwrite);
}
return this;
}
/**
* Set a value for a UTF-16 code unit.
* Note that a Trie2 stores separate values for
* supplementary code points in the lead surrogate range
* (accessed via the plain set() and get() interfaces)
* and for lead surrogate code units.
*
* The lead surrogate code unit values are set via this function and
* read by the function getFromU16SingleLead().
*
* For code units outside of the lead surrogate range, this function
* behaves identically to set().
*
* @param codeUnit A UTF-16 code unit.
* @param value the value to be stored in the Trie2.
*/
public Trie2Writable setForLeadSurrogateCodeUnit(char codeUnit, int value) {
fHash = 0;
set(codeUnit, false, value);
return this;
}
/**
* Get the value for a code point as stored in the Trie2.
*
* @param codePoint the code point
* @return the value
*/
@Override
public int get(int codePoint) {
if (codePoint<0 || codePoint>0x10ffff) {
return errorValue;
} else {
return get(codePoint, true);
}
}
private int get(int c, boolean fromLSCP) {
int i2, block;
if(c>=highStart && (!(c>=0xd800 && c<0xdc00) || fromLSCP)) {
return data[dataLength-UTRIE2_DATA_GRANULARITY];
}
if((c>=0xd800 && c<0xdc00) && fromLSCP) {
i2=(UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2))+
(c>>UTRIE2_SHIFT_2);
} else {
i2=index1[c>>UTRIE2_SHIFT_1]+
((c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK);
}
block=index2[i2];
return data[block+(c&UTRIE2_DATA_MASK)];
}
/**
* Get a trie value for a UTF-16 code unit.
*
* This function returns the same value as get() if the input
* character is outside of the lead surrogate range
*
* There are two values stored in a Trie for inputs in the lead
* surrogate range. This function returns the alternate value,
* while Trie2.get() returns the main value.
*
* @param c the code point or lead surrogate value.
* @return the value
*/
@Override
public int getFromU16SingleLead(char c) {
return get(c, false);
}
/* compaction --------------------------------------------------------------- */
private boolean equal_int(int[] a, int s, int t, int length) {
for (int i=0; i0) {
i2Block=index1[--i1];
if(i2Block==prevI2Block) {
/* the index-2 block is the same as the previous one, and filled with highValue */
c-=UTRIE2_CP_PER_INDEX_1_ENTRY;
continue;
}
prevI2Block=i2Block;
if(i2Block==index2NullOffset) {
/* this is the null index-2 block */
if(highValue!=initialValue) {
return c;
}
c-=UTRIE2_CP_PER_INDEX_1_ENTRY;
} else {
/* enumerate data blocks for one index-2 block */
for(i2=UTRIE2_INDEX_2_BLOCK_LENGTH; i2>0;) {
block=index2[i2Block+ --i2];
if(block==prevBlock) {
/* the block is the same as the previous one, and filled with highValue */
c-=UTRIE2_DATA_BLOCK_LENGTH;
continue;
}
prevBlock=block;
if(block==dataNullOffset) {
/* this is the null data block */
if(highValue!=initialValue) {
return c;
}
c-=UTRIE2_DATA_BLOCK_LENGTH;
} else {
for(j=UTRIE2_DATA_BLOCK_LENGTH; j>0;) {
value=data[block+ --j];
if(value!=highValue) {
return c;
}
--c;
}
}
}
}
}
/* deliver last range */
return 0;
}
/*
* Compact a build-time trie.
*
* The compaction
* - removes blocks that are identical with earlier ones
* - overlaps adjacent blocks as much as possible (if overlap==TRUE)
* - moves blocks in steps of the data granularity
* - moves and overlaps blocks that overlap with multiple values in the overlap region
*
* It does not
* - try to move and overlap blocks that are not already adjacent
*/
private void compactData() {
int start, newStart, movedStart;
int blockLength, overlap;
int i, mapIndex, blockCount;
/* do not compact linear-ASCII data */
newStart=UTRIE2_DATA_START_OFFSET;
for(start=0, i=0; start>UTRIE2_SHIFT_2;
for(start=newStart; start>UTRIE2_SHIFT_2]<=0) {
/* advance start to the next block */
start+=blockLength;
/* leave newStart with the previous block! */
continue;
}
/* search for an identical block */
movedStart=findSameDataBlock(newStart, start, blockLength);
if(movedStart >= 0) {
/* found an identical block, set the other block's index value for the current block */
for(i=blockCount, mapIndex=start>>UTRIE2_SHIFT_2; i>0; --i) {
map[mapIndex++]=movedStart;
movedStart+=UTRIE2_DATA_BLOCK_LENGTH;
}
/* advance start to the next block */
start+=blockLength;
/* leave newStart with the previous block! */
continue;
}
/* see if the beginning of this block can be overlapped with the end of the previous block */
/* look for maximum overlap (modulo granularity) with the previous, adjacent block */
for(overlap=blockLength-UTRIE2_DATA_GRANULARITY;
overlap>0 && !equal_int(data, (newStart-overlap), start, overlap);
overlap-=UTRIE2_DATA_GRANULARITY) {}
if(overlap>0 || newStart>UTRIE2_SHIFT_2; i>0; --i) {
map[mapIndex++]=movedStart;
movedStart+=UTRIE2_DATA_BLOCK_LENGTH;
}
/* move the non-overlapping indexes to their new positions */
start+=overlap;
for(i=blockLength-overlap; i>0; --i) {
data[newStart++]=data[start++];
}
} else /* no overlap && newStart==start */ {
for(i=blockCount, mapIndex=start>>UTRIE2_SHIFT_2; i>0; --i) {
map[mapIndex++]=start;
start+=UTRIE2_DATA_BLOCK_LENGTH;
}
newStart=start;
}
}
/* now adjust the index-2 table */
for(i=0; i>UTRIE2_SHIFT_2];
}
dataNullOffset=map[dataNullOffset>>UTRIE2_SHIFT_2];
/* ensure dataLength alignment */
while((newStart&(UTRIE2_DATA_GRANULARITY-1))!=0) {
data[newStart++]=initialValue;
}
if (UTRIE2_DEBUG) {
/* we saved some space */
System.out.printf("compacting UTrie2: count of 32-bit data words %d->%d\n",
dataLength, newStart);
}
dataLength=newStart;
}
private void compactIndex2() {
int i, start, newStart, movedStart, overlap;
/* do not compact linear-BMP index-2 blocks */
newStart=UTRIE2_INDEX_2_BMP_LENGTH;
for(start=0, i=0; start>UTRIE2_SHIFT_1);
for(start=UNEWTRIE2_INDEX_2_NULL_OFFSET; start=0
) {
/* found an identical block, set the other block's index value for the current block */
map[start>>UTRIE2_SHIFT_1_2]=movedStart;
/* advance start to the next block */
start+=UTRIE2_INDEX_2_BLOCK_LENGTH;
/* leave newStart with the previous block! */
continue;
}
/* see if the beginning of this block can be overlapped with the end of the previous block */
/* look for maximum overlap with the previous, adjacent block */
for(overlap=UTRIE2_INDEX_2_BLOCK_LENGTH-1;
overlap>0 && !equal_int(index2, newStart-overlap, start, overlap);
--overlap) {}
if(overlap>0 || newStart>UTRIE2_SHIFT_1_2]=newStart-overlap;
/* move the non-overlapping indexes to their new positions */
start+=overlap;
for(i=UTRIE2_INDEX_2_BLOCK_LENGTH-overlap; i>0; --i) {
index2[newStart++]=index2[start++];
}
} else /* no overlap && newStart==start */ {
map[start>>UTRIE2_SHIFT_1_2]=start;
start+=UTRIE2_INDEX_2_BLOCK_LENGTH;
newStart=start;
}
}
/* now adjust the index-1 table */
for(i=0; i>UTRIE2_SHIFT_1_2];
}
index2NullOffset=map[index2NullOffset>>UTRIE2_SHIFT_1_2];
/*
* Ensure data table alignment:
* Needs to be granularity-aligned for 16-bit trie
* (so that dataMove will be down-shiftable),
* and 2-aligned for uint32_t data.
*/
while((newStart&((UTRIE2_DATA_GRANULARITY-1)|1))!=0) {
/* Arbitrary value: 0x3fffc not possible for real data. */
index2[newStart++]=0x0000ffff<%d\n",
index2Length, newStart);
}
index2Length=newStart;
}
private void compactTrie() {
int localHighStart;
int suppHighStart;
int highValue;
/* find highStart and round it up */
highValue=get(0x10ffff);
localHighStart=findHighStart(highValue);
localHighStart=(localHighStart+(UTRIE2_CP_PER_INDEX_1_ENTRY-1))&~(UTRIE2_CP_PER_INDEX_1_ENTRY-1);
if(localHighStart==0x110000) {
highValue=errorValue;
}
/*
* Set trie->highStart only after utrie2_get32(trie, highStart).
* Otherwise utrie2_get32(trie, highStart) would try to read the highValue.
*/
this.highStart=localHighStart;
if (UTRIE2_DEBUG) {
System.out.printf("UTrie2: highStart U+%04x highValue 0x%x initialValue 0x%x\n",
highStart, highValue, initialValue);
}
if(highStart<0x110000) {
/* Blank out [highStart..10ffff] to release associated data blocks. */
suppHighStart= highStart<=0x10000 ? 0x10000 : highStart;
setRange(suppHighStart, 0x10ffff, initialValue, true);
}
compactData();
if(highStart>0x10000) {
compactIndex2();
} else {
if (UTRIE2_DEBUG) {
System.out.printf("UTrie2: highStart U+%04x count of 16-bit index-2 words %d->%d\n",
highStart, index2Length, UTRIE2_INDEX_1_OFFSET);
}
}
/*
* Store the highValue in the data array and round up the dataLength.
* Must be done after compactData() because that assumes that dataLength
* is a multiple of UTRIE2_DATA_BLOCK_LENGTH.
*/
data[dataLength++]=highValue;
while((dataLength&(UTRIE2_DATA_GRANULARITY-1))!=0) {
data[dataLength++]=initialValue;
}
isCompacted=true;
}
/**
* Produce an optimized, read-only Trie2_16 from this writable Trie.
* The data values outside of the range that will fit in a 16 bit
* unsigned value will be truncated.
*/
public Trie2_16 toTrie2_16() {
Trie2_16 frozenTrie = new Trie2_16();
freeze(frozenTrie, ValueWidth.BITS_16);
return frozenTrie;
}
/**
* Produce an optimized, read-only Trie2_32 from this writable Trie.
*
*/
public Trie2_32 toTrie2_32() {
Trie2_32 frozenTrie = new Trie2_32();
freeze(frozenTrie, ValueWidth.BITS_32);
return frozenTrie;
}
/**
* Maximum length of the runtime index array.
* Limited by its own 16-bit index values, and by uint16_t UTrie2Header.indexLength.
* (The actual maximum length is lower,
* (0x110000>>UTRIE2_SHIFT_2)+UTRIE2_UTF8_2B_INDEX_2_LENGTH+UTRIE2_MAX_INDEX_1_LENGTH.)
*/
private static final int UTRIE2_MAX_INDEX_LENGTH = 0xffff;
/**
* Maximum length of the runtime data array.
* Limited by 16-bit index values that are left-shifted by UTRIE2_INDEX_SHIFT,
* and by uint16_t UTrie2Header.shiftedDataLength.
*/
private static final int UTRIE2_MAX_DATA_LENGTH = 0xffff<0 if the data is moved to the end of the index array */
/* compact if necessary */
if(!isCompacted) {
compactTrie();
}
if(highStart<=0x10000) {
allIndexesLength=UTRIE2_INDEX_1_OFFSET;
} else {
allIndexesLength=index2Length;
}
if(valueBits==ValueWidth.BITS_16) {
dataMove=allIndexesLength;
} else {
dataMove=0;
}
/* are indexLength and dataLength within limits? */
if( /* for unshifted indexLength */
allIndexesLength>UTRIE2_MAX_INDEX_LENGTH ||
/* for unshifted dataNullOffset */
(dataMove+dataNullOffset)>0xffff ||
/* for unshifted 2-byte UTF-8 index-2 values */
(dataMove+UNEWTRIE2_DATA_0800_OFFSET)>0xffff ||
/* for shiftedDataLength */
(dataMove+dataLength)>UTRIE2_MAX_DATA_LENGTH) {
throw new UnsupportedOperationException("Trie2 data is too large.");
}
/* calculate the sizes of, and allocate, the index and data arrays */
int indexLength = allIndexesLength;
if (valueBits==ValueWidth.BITS_16) {
indexLength += dataLength;
} else {
dest.data32 = new int[dataLength];
}
dest.index = new char[indexLength];
dest.indexLength = allIndexesLength;
dest.dataLength = dataLength;
if(highStart<=0x10000) {
dest.index2NullOffset = 0xffff;
} else {
dest.index2NullOffset = UTRIE2_INDEX_2_OFFSET + index2NullOffset;
}
dest.initialValue = initialValue;
dest.errorValue = errorValue;
dest.highStart = highStart;
dest.highValueIndex = dataMove + dataLength - UTRIE2_DATA_GRANULARITY;
dest.dataNullOffset = (dataMove+dataNullOffset);
// Create a header and set the its fields.
// (This is only used in the event that we serialize the Trie, but is
// convenient to do here.)
dest.header = new Trie2.UTrie2Header();
dest.header.signature = 0x54726932; /* "Tri2" */
dest.header.options = valueBits==ValueWidth.BITS_16 ? 0 : 1;
dest.header.indexLength = dest.indexLength;
dest.header.shiftedDataLength = dest.dataLength>>UTRIE2_INDEX_SHIFT;
dest.header.index2NullOffset = dest.index2NullOffset;
dest.header.dataNullOffset = dest.dataNullOffset;
dest.header.shiftedHighStart = dest.highStart>>UTRIE2_SHIFT_1;
/* write the index-2 array values shifted right by UTRIE2_INDEX_SHIFT, after adding dataMove */
int destIdx = 0;
for(i=0; i> UTRIE2_INDEX_SHIFT);
}
if (UTRIE2_DEBUG) {
System.out.println("\n\nIndex2 for BMP limit is " + Integer.toHexString(destIdx));
}
/* write UTF-8 2-byte index-2 values, not right-shifted */
for(i=0; i<(0xc2-0xc0); ++i) { /* C0..C1 */
dest.index[destIdx++] = (char)(dataMove+UTRIE2_BAD_UTF8_DATA_OFFSET);
}
for(; i<(0xe0-0xc0); ++i) { /* C2..DF */
dest.index[destIdx++]=(char)(dataMove+index2[i<<(6-UTRIE2_SHIFT_2)]);
}
if (UTRIE2_DEBUG) {
System.out.println("Index2 for UTF-8 2byte values limit is " + Integer.toHexString(destIdx));
}
if(highStart>0x10000) {
int index1Length = (highStart-0x10000)>>UTRIE2_SHIFT_1;
int index2Offset = UTRIE2_INDEX_2_BMP_LENGTH + UTRIE2_UTF8_2B_INDEX_2_LENGTH + index1Length;
/* write 16-bit index-1 values for supplementary code points */
//p=(uint32_t *)newTrie->index1+UTRIE2_OMITTED_BMP_INDEX_1_LENGTH;
for(i=0; i>UTRIE2_INDEX_SHIFT);
}
if (UTRIE2_DEBUG) {
System.out.println("Index 2 for supplementals, limit is " + Integer.toHexString(destIdx));
}
}
/* write the 16/32-bit data array */
switch(valueBits) {
case BITS_16:
/* write 16-bit data values */
assert(destIdx == dataMove);
dest.data16 = destIdx;
for(i=0; i0: reference counter (number of index-2 entries pointing here)
* <0: next free data block in free-block list
*
* While compacting:
*
* Map of adjusted indexes, used in compactData() and compactIndex2().
* Maps from original indexes to new ones.
*/
private int[] map = new int[UNEWTRIE2_MAX_DATA_LENGTH>>UTRIE2_SHIFT_2];
private boolean UTRIE2_DEBUG = false;
}