001: /*
002: * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.text;
027:
028: public final class UCompactIntArray implements Cloneable {
029: /**
030: * Default constructor for UCompactIntArray, the default value of the
031: * compact array is 0.
032: */
033: public UCompactIntArray() {
034: values = new int[16][];
035: indices = new short[16][];
036: blockTouched = new boolean[16][];
037: planeTouched = new boolean[16];
038: }
039:
040: public UCompactIntArray(int defaultValue) {
041: this ();
042: this .defaultValue = defaultValue;
043: }
044:
045: /**
046: * Get the mapped value of a Unicode character.
047: * @param index the character to get the mapped value with
048: * @return the mapped value of the given character
049: */
050: public int elementAt(int index) {
051: int plane = (index & PLANEMASK) >> PLANESHIFT;
052: if (!planeTouched[plane]) {
053: return defaultValue;
054: }
055: index &= CODEPOINTMASK;
056: return values[plane][(indices[plane][index >> BLOCKSHIFT] & 0xFFFF)
057: + (index & BLOCKMASK)];
058: }
059:
060: /**
061: * Set a new value for a Unicode character.
062: * Set automatically expands the array if it is compacted.
063: * @param index the character to set the mapped value with
064: * @param value the new mapped value
065: */
066: public void setElementAt(int index, int value) {
067: if (isCompact) {
068: expand();
069: }
070: int plane = (index & PLANEMASK) >> PLANESHIFT;
071: if (!planeTouched[plane]) {
072: initPlane(plane);
073: }
074: index &= CODEPOINTMASK;
075: values[plane][index] = value;
076: blockTouched[plane][index >> BLOCKSHIFT] = true;
077: }
078:
079: /**
080: * Compact the array.
081: */
082: public void compact() {
083: if (isCompact) {
084: return;
085: }
086: for (int plane = 0; plane < PLANECOUNT; plane++) {
087: if (!planeTouched[plane]) {
088: continue;
089: }
090: int limitCompacted = 0;
091: int iBlockStart = 0;
092: short iUntouched = -1;
093:
094: for (int i = 0; i < indices[plane].length; ++i, iBlockStart += BLOCKCOUNT) {
095: indices[plane][i] = -1;
096: if (!blockTouched[plane][i] && iUntouched != -1) {
097: // If no values in this block were set, we can just set its
098: // index to be the same as some other block with no values
099: // set, assuming we've seen one yet.
100: indices[plane][i] = iUntouched;
101: } else {
102: int jBlockStart = limitCompacted * BLOCKCOUNT;
103: if (i > limitCompacted) {
104: System.arraycopy(values[plane], iBlockStart,
105: values[plane], jBlockStart, BLOCKCOUNT);
106: }
107: if (!blockTouched[plane][i]) {
108: // If this is the first untouched block we've seen, remember it.
109: iUntouched = (short) jBlockStart;
110: }
111: indices[plane][i] = (short) jBlockStart;
112: limitCompacted++;
113: }
114: }
115:
116: // we are done compacting, so now make the array shorter
117: int newSize = limitCompacted * BLOCKCOUNT;
118: int[] result = new int[newSize];
119: System.arraycopy(values[plane], 0, result, 0, newSize);
120: values[plane] = result;
121: blockTouched[plane] = null;
122: }
123: isCompact = true;
124: }
125:
126: // --------------------------------------------------------------
127: // private
128: // --------------------------------------------------------------
129: /**
130: * Expanded takes the array back to a 0x10ffff element array
131: */
132: private void expand() {
133: int i;
134: if (isCompact) {
135: int[] tempArray;
136: for (int plane = 0; plane < PLANECOUNT; plane++) {
137: if (!planeTouched[plane]) {
138: continue;
139: }
140: blockTouched[plane] = new boolean[INDEXCOUNT];
141: tempArray = new int[UNICODECOUNT];
142: for (i = 0; i < UNICODECOUNT; ++i) {
143: tempArray[i] = values[plane][indices[plane][i >> BLOCKSHIFT]
144: & 0xffff + (i & BLOCKMASK)];
145: blockTouched[plane][i >> BLOCKSHIFT] = true;
146: }
147: for (i = 0; i < INDEXCOUNT; ++i) {
148: indices[plane][i] = (short) (i << BLOCKSHIFT);
149: }
150: values[plane] = tempArray;
151: }
152: isCompact = false;
153: }
154: }
155:
156: private void initPlane(int plane) {
157: values[plane] = new int[UNICODECOUNT];
158: indices[plane] = new short[INDEXCOUNT];
159: blockTouched[plane] = new boolean[INDEXCOUNT];
160: planeTouched[plane] = true;
161:
162: if (planeTouched[0] && plane != 0) {
163: System.arraycopy(indices[0], 0, indices[plane], 0,
164: INDEXCOUNT);
165: } else {
166: for (int i = 0; i < INDEXCOUNT; ++i) {
167: indices[plane][i] = (short) (i << BLOCKSHIFT);
168: }
169: }
170: for (int i = 0; i < UNICODECOUNT; ++i) {
171: values[plane][i] = defaultValue;
172: }
173: }
174:
175: public int getKSize() {
176: int size = 0;
177: for (int plane = 0; plane < PLANECOUNT; plane++) {
178: if (planeTouched[plane]) {
179: size += (values[plane].length * 4 + indices[plane].length * 2);
180: }
181: }
182: return size / 1024;
183: }
184:
185: private static final int PLANEMASK = 0x30000;
186: private static final int PLANESHIFT = 16;
187: private static final int PLANECOUNT = 0x10;
188: private static final int CODEPOINTMASK = 0xffff;
189:
190: private static final int UNICODECOUNT = 0x10000;
191: private static final int BLOCKSHIFT = 7;
192: private static final int BLOCKCOUNT = (1 << BLOCKSHIFT);
193: private static final int INDEXSHIFT = (16 - BLOCKSHIFT);
194: private static final int INDEXCOUNT = (1 << INDEXSHIFT);
195: private static final int BLOCKMASK = BLOCKCOUNT - 1;
196:
197: private int defaultValue;
198: private int values[][];
199: private short indices[][];
200: private boolean isCompact;
201: private boolean[][] blockTouched;
202: private boolean[] planeTouched;
203: };
|