• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2016 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 /*
5  *******************************************************************************
6  * Copyright (C) 1996-2014, International Business Machines Corporation and    *
7  * others. All Rights Reserved.                                                *
8  *******************************************************************************
9  */
10 
11 package android.icu.util;
12 
13 import android.icu.impl.Utility;
14 
15 /**
16  * class CompactATypeArray : use only on primitive data types
17  * Provides a compact way to store information that is indexed by Unicode
18  * values, such as character properties, types, keyboard values, etc.This
19  * is very useful when you have a block of Unicode data that contains
20  * significant values while the rest of the Unicode data is unused in the
21  * application or when you have a lot of redundance, such as where all 21,000
22  * Han ideographs have the same value.  However, lookup is much faster than a
23  * hash table.
24  * A compact array of any primitive data type serves two purposes:
25  * <UL type = round>
26  *     <LI>Fast access of the indexed values.
27  *     <LI>Smaller memory footprint.
28  * </UL>
29  * A compact array is composed of a index array and value array.  The index
30  * array contains the indicies of Unicode characters to the value array.
31  * @see                CompactByteArray
32  * @author             Helena Shih
33  * @deprecated This API is ICU internal only.
34  * @hide Only a subset of ICU is exposed in Android
35  * @hide draft / provisional / internal are hidden on Android
36  */
37 @Deprecated
38 public final class CompactCharArray implements Cloneable {
39 
40     /**
41      * The total number of Unicode characters.
42      * @deprecated This API is ICU internal only.
43      * @hide draft / provisional / internal are hidden on Android
44      */
45     @Deprecated
46     public static  final int UNICODECOUNT = 65536;
47 
48     /**
49      * Default constructor for CompactCharArray, the default value of the
50      * compact array is 0.
51      * @deprecated This API is ICU internal only.
52      * @hide draft / provisional / internal are hidden on Android
53      */
54     @Deprecated
CompactCharArray()55     public CompactCharArray()
56     {
57         this((char)0);
58     }
59 
60     /**
61      * Constructor for CompactCharArray.
62      * @param defaultValue the default value of the compact array.
63      * @deprecated This API is ICU internal only.
64      * @hide draft / provisional / internal are hidden on Android
65      */
66     @Deprecated
CompactCharArray(char defaultValue)67     public CompactCharArray(char defaultValue)
68     {
69         int i;
70         values = new char[UNICODECOUNT];
71         indices = new char[INDEXCOUNT];
72         hashes = new int[INDEXCOUNT];
73         for (i = 0; i < UNICODECOUNT; ++i) {
74             values[i] = defaultValue;
75         }
76         for (i = 0; i < INDEXCOUNT; ++i) {
77             indices[i] = (char)(i<<BLOCKSHIFT);
78             hashes[i] = 0;
79         }
80         isCompact = false;
81 
82         this.defaultValue = defaultValue;
83     }
84 
85     /**
86      * Constructor for CompactCharArray.
87      * @param indexArray the indicies of the compact array.
88      * @param newValues the values of the compact array.
89      * @exception IllegalArgumentException If the index is out of range.
90      * @deprecated This API is ICU internal only.
91      * @hide draft / provisional / internal are hidden on Android
92      */
93     @Deprecated
CompactCharArray(char indexArray[], char newValues[])94     public CompactCharArray(char indexArray[],
95                              char newValues[])
96     {
97         int i;
98         if (indexArray.length != INDEXCOUNT)
99             throw new IllegalArgumentException("Index out of bounds.");
100         for (i = 0; i < INDEXCOUNT; ++i) {
101             char index = indexArray[i];
102             if (index >= newValues.length+BLOCKCOUNT)
103                 throw new IllegalArgumentException("Index out of bounds.");
104         }
105         indices = indexArray;
106         values = newValues;
107         isCompact = true;
108     }
109 
110     /**
111      * Constructor for CompactCharArray.
112      *
113      * @param indexArray the RLE-encoded indicies of the compact array.
114      * @param valueArray the RLE-encoded values of the compact array.
115      *
116      * @throws IllegalArgumentException if the index or value array is
117      *          the wrong size.
118      * @deprecated This API is ICU internal only.
119      * @hide draft / provisional / internal are hidden on Android
120      */
121     @Deprecated
CompactCharArray(String indexArray, String valueArray)122     public CompactCharArray(String indexArray,
123                 String valueArray)
124     {
125         this( Utility.RLEStringToCharArray(indexArray),
126               Utility.RLEStringToCharArray(valueArray));
127     }
128 
129     /**
130      * Get the mapped value of a Unicode character.
131      * @param index the character to get the mapped value with
132      * @return the mapped value of the given character
133      * @deprecated This API is ICU internal only.
134      * @hide draft / provisional / internal are hidden on Android
135      */
136     @Deprecated
elementAt(char index)137     public char elementAt(char index)
138     {
139     int ix = (indices[index >> BLOCKSHIFT] & 0xFFFF)
140         + (index & BLOCKMASK);
141     return ix >= values.length ? defaultValue : values[ix];
142     }
143 
144     /**
145      * Set a new value for a Unicode character.
146      * Set automatically expands the array if it is compacted.
147      * @param index the character to set the mapped value with
148      * @param value the new mapped value
149      * @deprecated This API is ICU internal only.
150      * @hide draft / provisional / internal are hidden on Android
151      */
152     @Deprecated
setElementAt(char index, char value)153     public void setElementAt(char index, char value)
154     {
155         if (isCompact)
156             expand();
157          values[index] = value;
158         touchBlock(index >> BLOCKSHIFT, value);
159     }
160 
161     /**
162      * Set new values for a range of Unicode character.
163      *
164      * @param start the starting offset of the range
165      * @param end the ending offset of the range
166      * @param value the new mapped value
167      * @deprecated This API is ICU internal only.
168      * @hide draft / provisional / internal are hidden on Android
169      */
170     @Deprecated
setElementAt(char start, char end, char value)171     public void setElementAt(char start, char end, char value)
172     {
173         int i;
174         if (isCompact) {
175             expand();
176         }
177         for (i = start; i <= end; ++i) {
178             values[i] = value;
179             touchBlock(i >> BLOCKSHIFT, value);
180         }
181     }
182     /**
183      * Compact the array
184      * @deprecated This API is ICU internal only.
185      * @hide draft / provisional / internal are hidden on Android
186      */
187     @Deprecated
compact()188     public void compact() {
189         compact(true);
190     }
191 
192     /**
193      * Compact the array.
194      * @deprecated This API is ICU internal only.
195      * @hide draft / provisional / internal are hidden on Android
196      */
197     @Deprecated
compact(boolean exhaustive)198     public void compact(boolean exhaustive)
199     {
200         if (!isCompact) {
201             int iBlockStart = 0;
202             char iUntouched = 0xFFFF;
203             int newSize = 0;
204 
205             char[] target = exhaustive ? new char[UNICODECOUNT] : values;
206 
207             for (int i = 0; i < indices.length; ++i, iBlockStart += BLOCKCOUNT) {
208                 indices[i] = 0xFFFF;
209                 boolean touched = blockTouched(i);
210                 if (!touched && iUntouched != 0xFFFF) {
211                     // If no values in this block were set, we can just set its
212                     // index to be the same as some other block with no values
213                     // set, assuming we've seen one yet.
214                     indices[i] = iUntouched;
215                 } else {
216                     int jBlockStart = 0;
217                     // See if we can find a previously compacted block that's identical
218                     for (int j = 0; j < i; ++j, jBlockStart += BLOCKCOUNT) {
219                         if (hashes[i] == hashes[j] &&
220                                 arrayRegionMatches(values, iBlockStart,
221                                                    values, jBlockStart, BLOCKCOUNT)) {
222                             indices[i] = indices[j];
223                         }
224                     }
225                     if (indices[i] == 0xFFFF) {
226                         int dest;   // Where to copy
227                         if (exhaustive) {
228                             // See if we can find some overlap with another block
229                             dest = FindOverlappingPosition(iBlockStart, target,
230                                                             newSize);
231                         } else {
232                             // Just copy to the end; it's quicker
233                             dest = newSize;
234                         }
235                         int limit = dest + BLOCKCOUNT;
236                         if (limit > newSize) {
237                             for (int j = newSize; j < limit; ++j) {
238                                 target[j] = values[iBlockStart + j - dest];
239                             }
240                             newSize = limit;
241                         }
242                         indices[i] = (char)dest;
243                         if (!touched) {
244                             // If this is the first untouched block we've seen,
245                             // remember its index.
246                             iUntouched = (char)jBlockStart;
247                         }
248                     }
249                 }
250             }
251             // we are done compacting, so now make the array shorter
252             char[] result = new char[newSize];
253             System.arraycopy(target, 0, result, 0, newSize);
254             values = result;
255             isCompact = true;
256             hashes = null;
257         }
258     }
259 
FindOverlappingPosition(int start, char[] tempValues, int tempCount)260     private int FindOverlappingPosition(int start, char[] tempValues, int tempCount)
261     {
262         for (int i = 0; i < tempCount; i += 1) {
263             int currentCount = BLOCKCOUNT;
264             if (i + BLOCKCOUNT > tempCount) {
265                 currentCount = tempCount - i;
266             }
267             if (arrayRegionMatches(values, start, tempValues, i, currentCount))
268                 return i;
269         }
270         return tempCount;
271     }
272 
273     /**
274      * Convenience utility to compare two arrays of doubles.
275      * @param len the length to compare.
276      * The start indices and start+len must be valid.
277      */
arrayRegionMatches(char[] source, int sourceStart, char[] target, int targetStart, int len)278     final static boolean arrayRegionMatches(char[] source, int sourceStart,
279                                             char[] target, int targetStart,
280                                             int len)
281     {
282         int sourceEnd = sourceStart + len;
283         int delta = targetStart - sourceStart;
284         for (int i = sourceStart; i < sourceEnd; i++) {
285             if (source[i] != target[i + delta])
286             return false;
287         }
288         return true;
289     }
290 
291     /**
292      * Remember that a specified block was "touched", i.e. had a value set.
293      * Untouched blocks can be skipped when compacting the array
294      */
touchBlock(int i, int value)295     private final void touchBlock(int i, int value) {
296         hashes[i] = (hashes[i] + (value<<1)) | 1;
297     }
298 
299     /**
300      * Query whether a specified block was "touched", i.e. had a value set.
301      * Untouched blocks can be skipped when compacting the array
302      */
blockTouched(int i)303     private final boolean blockTouched(int i) {
304         return hashes[i] != 0;
305     }
306 
307     /**
308      * For internal use only.  Do not modify the result, the behavior of
309      * modified results are undefined.
310      * @deprecated This API is ICU internal only.
311      * @hide draft / provisional / internal are hidden on Android
312      */
313     @Deprecated
getIndexArray()314     public char[] getIndexArray()
315     {
316         return indices;
317     }
318 
319     /**
320      * For internal use only.  Do not modify the result, the behavior of
321      * modified results are undefined.
322      * @deprecated This API is ICU internal only.
323      * @hide draft / provisional / internal are hidden on Android
324      */
325     @Deprecated
getValueArray()326     public char[] getValueArray()
327     {
328         return values;
329     }
330 
331     /**
332      * Overrides Cloneable
333      * @deprecated This API is ICU internal only.
334      * @hide draft / provisional / internal are hidden on Android
335      */
336     @Override
337     @Deprecated
clone()338     public Object clone()
339     {
340         try {
341             CompactCharArray other = (CompactCharArray) super.clone();
342             other.values = values.clone();
343             other.indices = indices.clone();
344             if (hashes != null) other.hashes = hashes.clone();
345             return other;
346         } catch (CloneNotSupportedException e) {
347             throw new ICUCloneNotSupportedException(e);
348         }
349     }
350 
351     /**
352      * Compares the equality of two compact array objects.
353      * @param obj the compact array object to be compared with this.
354      * @return true if the current compact array object is the same
355      * as the compact array object obj; false otherwise.
356      * @deprecated This API is ICU internal only.
357      * @hide draft / provisional / internal are hidden on Android
358      */
359     @Override
360     @Deprecated
equals(Object obj)361     public boolean equals(Object obj) {
362         if (obj == null) return false;
363         if (this == obj)                      // quick check
364             return true;
365         if (getClass() != obj.getClass())         // same class?
366             return false;
367         CompactCharArray other = (CompactCharArray) obj;
368         for (int i = 0; i < UNICODECOUNT; i++) {
369             // could be sped up later
370             if (elementAt((char)i) != other.elementAt((char)i))
371                 return false;
372         }
373         return true; // we made it through the guantlet.
374     }
375 
376     /**
377      * Generates the hash code for the compact array object
378      * @deprecated This API is ICU internal only.
379      * @hide draft / provisional / internal are hidden on Android
380      */
381     @Override
382     @Deprecated
hashCode()383     public int hashCode() {
384         int result = 0;
385         int increment = Math.min(3, values.length/16);
386         for (int i = 0; i < values.length; i+= increment) {
387             result = result * 37 + values[i];
388         }
389         return result;
390     }
391 
392 
393     // --------------------------------------------------------------
394     // private
395     // --------------------------------------------------------------
396 
397     /**
398      * Expanding takes the array back to a 65536 element array.
399      */
expand()400     private void expand()
401     {
402         int i;
403         if (isCompact) {
404             char[] tempArray;
405             hashes = new int[INDEXCOUNT];
406             tempArray = new char[UNICODECOUNT];
407             for (i = 0; i < UNICODECOUNT; ++i) {
408                 tempArray[i] = elementAt((char)i);
409             }
410             for (i = 0; i < INDEXCOUNT; ++i) {
411                 indices[i] = (char)(i<<BLOCKSHIFT);
412             }
413             values = null;
414             values = tempArray;
415             isCompact = false;
416         }
417     }
418     /**
419      * @deprecated This API is ICU internal only.
420      * @hide draft / provisional / internal are hidden on Android
421      */
422     @Deprecated
423     public static  final int BLOCKSHIFT = 5; // NormalizerBuilder needs - liu
424     static  final int BLOCKCOUNT =(1<<BLOCKSHIFT);
425     static  final int INDEXSHIFT =(16-BLOCKSHIFT);
426     static  final int INDEXCOUNT =(1<<INDEXSHIFT);
427     static  final int BLOCKMASK = BLOCKCOUNT - 1;
428 
429     private char values[];
430     private char indices[];
431     private int[] hashes;
432     private boolean isCompact;
433     char defaultValue;
434 }
435