home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / CompactStringArray.java < prev    next >
Text File  |  1997-05-20  |  17KB  |  450 lines

  1. /*
  2.  * @(#)CompactStringArray.java    1.8 97/01/27
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.text;
  32.  
  33. /**
  34.  * class CompactATypeArray : use only on primitive data types
  35.  * Provides a compact way to store information that is indexed by Unicode
  36.  * values, such as character properties, types, keyboard values, etc.This
  37.  * is very useful when you have a block of Unicode data that contains
  38.  * significant values while the rest of the Unicode data is unused in the
  39.  * application or when you have a lot of redundance, such as where all 21,000
  40.  * Han ideographs have the same value.  However, lookup is much faster than a
  41.  * hash table.
  42.  * A compact array of any primitive data type serves two purposes:
  43.  * <UL type = round>
  44.  *     <LI>Fast access of the indexed values.
  45.  *     <LI>Smaller memory footprint.
  46.  * </UL>
  47.  * A compact array is composed of a index array and value array.  The index
  48.  * array contains the indicies of Unicode characters to the value array.
  49.  *
  50.  * @see                CompactShortArray
  51.  * @see                CompactByteArray
  52.  * @see                CompactIntArray
  53.  * @see                CompactCharArray
  54.  * @version            1.8 01/27/97
  55.  * @author             Helena Shih
  56.  */
  57. final class CompactStringArray implements Cloneable {
  58.  
  59.     /**
  60.      * The total number of Unicode characters.
  61.      */
  62.     public static  final int UNICODECOUNT =65536;
  63.  
  64.     /**
  65.      * Default constructor for CompactStringArray, the default value of the
  66.      * compact array is "".
  67.      */
  68.     public CompactStringArray()
  69.     {
  70.         this("");
  71.     }
  72.     /**
  73.      * Constructor for CompactStringArray.
  74.      * @param defaultValue the default value of the compact array.
  75.      */
  76.     public CompactStringArray(String defaultValue)
  77.     {
  78.         int i;
  79.         values = new char[UNICODECOUNT]; /*type = char*/
  80.         indices = new short[INDEXCOUNT];
  81.         setElementAt((char)0,'\uFFFF',defaultValue);
  82.         for (i = 0; i < INDEXCOUNT; ++i) {
  83.             indices[i] = (short)(i<<BLOCKSHIFT);
  84.         }
  85.         isCompact = false;
  86.     }
  87.     /**
  88.      * Constructor for CompactStringArray.
  89.      * @param indexArray the indicies of the compact array.
  90.      * @param newValues the values of the compact array.
  91.      * @exception IllegalArgumentException If the index is out of range.
  92.      */
  93.     public CompactStringArray(short indexArray[],
  94.                               char[] newValues,
  95.                               String exceptions)
  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.             short index = indexArray[i];
  102.             if ((index < 0) || (index >= newValues.length+BLOCKCOUNT))
  103.                 throw new IllegalArgumentException("Index out of bounds.");
  104.         }
  105.         indices = indexArray;
  106.         values = newValues;
  107.     }
  108.     /**
  109.      * Get the mapped value (String) of a Unicode character.
  110.      * @param index the character to get the mapped value with
  111.      * @param toAppendTo the string buffer to append the values to
  112.      */
  113.     public void elementAt(char index, StringBuffer toAppendTo)
  114.     {
  115.         char result = (values[(indices[index>>BLOCKSHIFT] & 0xFFFF) +
  116.                              (index & BLOCKMASK)]);
  117.         if (result >= '\uE000' && result <= '\uF800') {
  118.             for (int i = (int) result - 0xE000; ; ++i) {
  119.                 result = exceptions.charAt(i);
  120.                 if (result == '\uFFFF') return;
  121.                 toAppendTo.append(result);
  122.             }
  123.         } else {
  124.             toAppendTo.append(result);
  125.         }
  126.     }
  127.     /**
  128.      * Get the mapped value of a Unicode character.
  129.      * @param index the character to get the mapped value with
  130.      * @return the mapped value of the given character
  131.      */
  132.     public String elementAt(char index) {
  133.         StringBuffer result = new StringBuffer();
  134.         elementAt(index,result);
  135.         return result.toString();
  136.     }
  137.     /**
  138.      * Set a new value for a Unicode character.
  139.      * Set automatically expands the array if it is compacted.
  140.      * @param index the character to set the mapped value with
  141.      * @param value the new mapped value
  142.      */
  143.     public void setElementAt(char index, String value)
  144.     {
  145.         if (isCompact)
  146.             expand();
  147.         if (value.length() == 1) {
  148.             char ch = value.charAt(0);
  149.             if (ch < '\uE000' || ch >= '\uF800') {
  150.                 values[(int)index] = ch;
  151.                 return;
  152.             }
  153.         }
  154.         // search for the string to see if it is already present
  155.         String temp = value + '\uFFFF';
  156.         int position = exceptions.toString().indexOf(temp);
  157.         if (position != -1) {
  158.             values[(int)index] = (char)(0xE000 + position);
  159.             return;
  160.         };
  161.         // if not found, append.
  162.         values[(int)index] = (char) (0xE000 + exceptions.length());
  163.         for (int i = 0; i < value.length(); ++i) {
  164.             exceptions.append(value.charAt(i));
  165.         }
  166.         exceptions.append('\uFFFF');    // termination
  167.     }
  168.     /**
  169.      * Set new values for a range of Unicode character.
  170.      * @param start the starting offset of the range
  171.      * @param end the ending offset of the range
  172.      * @param value the new mapped value
  173.      */
  174.    public void setElementAt(char start, char end, String value)
  175.     {
  176.         if (start >= end) return; // catch degenerate case
  177.         setElementAt(start,value);
  178.         char firstValue = values[(int)start];
  179.         for (int i = start + 1; i <= end; ++i) {
  180.             values[i] = firstValue;
  181.         }
  182.     }
  183.     /**
  184.      * Compact the array.
  185.      */
  186.     public void compact()
  187.     {
  188.         if (isCompact == false) {
  189.             char[]      tempIndex;
  190.             int                     tempIndexCount;
  191.             char[]          tempArray;
  192.             short           iBlock, iIndex;
  193.  
  194.             // make temp storage, larger than we need
  195.             tempIndex = new char[UNICODECOUNT];
  196.             // set up first block.
  197.             tempIndexCount = BLOCKCOUNT;
  198.             for (iIndex = 0; iIndex < BLOCKCOUNT; ++iIndex) {
  199.                 tempIndex[iIndex] = (char)iIndex;
  200.             }; // endfor (iIndex = 0; .....)
  201.             indices[0] = (short)0;
  202.  
  203.             // for each successive block, find out its first position
  204.             // in the compacted array
  205.             for (iBlock = 1; iBlock < INDEXCOUNT; ++iBlock) {
  206.                 int     newCount, firstPosition, block;
  207.                 block = iBlock<<BLOCKSHIFT;
  208.                 if (DEBUGSMALL) if (block > DEBUGSMALLLIMIT) break;
  209.                 firstPosition = FindOverlappingPosition(block, tempIndex,
  210.                                                         tempIndexCount);
  211.  
  212.                 newCount = firstPosition + BLOCKCOUNT;
  213.                 if (newCount > tempIndexCount) {
  214.                     for (iIndex = (short)tempIndexCount;
  215.                          iIndex < newCount;
  216.                          ++iIndex) {
  217.                         tempIndex[iIndex]
  218.                             = (char)(iIndex - firstPosition + block);
  219.                     } // endfor (iIndex = tempIndexCount....)
  220.                     tempIndexCount = newCount;
  221.                 } // endif (newCount > tempIndexCount)
  222.                 indices[iBlock] = (short)firstPosition;
  223.             } // endfor (iBlock = 1.....)
  224.  
  225.             // now allocate and copy the items into the array
  226.             tempArray = new char[tempIndexCount];
  227.             for (iIndex = 0; iIndex < tempIndexCount; ++iIndex) {
  228.                 tempArray[iIndex] = values[tempIndex[iIndex]];
  229.             }
  230.             values = null;
  231.             values = tempArray;
  232.             isCompact = true;
  233.         } // endif (isCompact != false)
  234.     }
  235.     /** For internal use only.  Do not modify the result, the behavior of
  236.      * modified results are undefined.
  237.      */
  238.     public short getIndexArray()[]
  239.     {
  240.         return indices;
  241.     }
  242.     /** For internal use only.  Do not modify the result, the behavior of
  243.       * modified results are undefined.
  244.       */
  245.     public char getStringArray()[]
  246.     {
  247.         return values;
  248.     }
  249.     /**
  250.      * Overrides Cloneable
  251.      */
  252.     public Object clone()
  253.     {
  254.         try {
  255.             CompactStringArray other = (CompactStringArray) super.clone();
  256.             other.values = (char[])values.clone();
  257.             other.indices = (short[])indices.clone();
  258.             other.exceptions = new StringBuffer(exceptions.toString());
  259.             return other;
  260.         } catch (CloneNotSupportedException e) {
  261.             throw new InternalError();
  262.         }
  263.     }
  264.     /**
  265.      * Compares the equality of two compact array objects.
  266.      * @param obj the compact array object to be compared with this.
  267.      * @return true if the current compact array object is the same
  268.      * as the compact array object obj; false otherwise.
  269.      */
  270.     public boolean equals(Object obj) {
  271.         if (this == obj)                      // quick check
  272.             return true;
  273.         if (getClass() != obj.getClass())         // same class?
  274.             return false;
  275.         CompactStringArray other = (CompactStringArray) obj;
  276.         for (int i = 0; i < UNICODECOUNT; i++) {
  277.             // could be sped up later
  278.             if (elementAt((char)i) != other.elementAt((char)i))
  279.                 return false;
  280.         }
  281.         return true; // we made it through the guantlet.
  282.     }
  283.     /**
  284.      * Generates the hash code for the compact array object
  285.      */
  286.  
  287.     public int hashCode() {
  288.         int result = 0;
  289.         int increment = Math.min(3, values.length/16);
  290.         for (int i = 0; i < values.length; i+= increment) {
  291.             result = result * 37 + values[i];
  292.         }
  293.         return result;
  294.     }
  295.     /**
  296.       * package private : for internal use only
  297.       */
  298.     void writeArrays()
  299.     {
  300.         int i;
  301.         int cnt = 0;
  302.         if (values.length > 0)
  303.             cnt = values.length;
  304.         else
  305.             cnt = values.length + UNICODECOUNT;
  306.         System.out.println("{");
  307.         for (i = 0; i < INDEXCOUNT-1; i++)
  308.         {
  309.             System.out.print("(short)" + (int)((getIndexArrayValue(i) >= 0) ?
  310.                 (int)getIndexArrayValue(i) :
  311.                 (int)(getIndexArrayValue(i)+UNICODECOUNT)) + ", ");
  312.             if (i != 0)
  313.                 if (i % 10 == 0)
  314.                     System.out.println();
  315.         }
  316.         System.out.println("(char)" +
  317.                            (int)((getIndexArrayValue(INDEXCOUNT-1) >= 0) ?
  318.                            (int)getIndexArrayValue(i) :
  319.                            (int)(getIndexArrayValue(i)+UNICODECOUNT)) + " }");
  320.         System.out.println("{");
  321.         for (i = 0; i < cnt-1; i++)
  322.         {
  323.             char ch = getArrayValue(i);
  324.             if (ch < 0x20 || (ch > 0x7E && ch < 0xA0) || ch > 0x100)
  325.                 System.out.print("(char)0x" +
  326.                     Integer.toString((int)ch,16).toUpperCase() + ",");
  327.             else System.out.print("\'" + ch + "\',");
  328.             if (i != 0)
  329.                 if (i % 10 == 0)
  330.                     System.out.println();
  331.         }
  332.         System.out.println("(char)" + (int)getArrayValue(cnt-1) + " }");
  333.         System.out.println("\"" + exceptions.toString() + "\"");
  334.     }
  335.     // Print char Array  : Debug only
  336.     void printIndex(char start, short count)
  337.     {
  338.         int i;
  339.         for (i = start; i < count; ++i)
  340.         {
  341.             System.out.println(i + " -> : " +
  342.                                (int)((indices[i] >= 0) ?
  343.                                      indices[i] : indices[i] + UNICODECOUNT));
  344.         }
  345.         System.out.println();
  346.     }
  347.     void printPlainArray(int start,int count, char[] tempIndex)
  348.     {
  349.         int iIndex;
  350.         if (tempIndex != null)
  351.         {
  352.             for (iIndex     = start; iIndex < start + count; ++iIndex)
  353.             {
  354.                 System.out.print(" " + (int)getArrayValue(tempIndex[iIndex]));
  355.             }
  356.         }
  357.         else
  358.         {
  359.             for (iIndex = start; iIndex < start + count; ++iIndex)
  360.             {
  361.                 System.out.print(" " + (int)getArrayValue(iIndex));
  362.             }
  363.         }
  364.         System.out.println("    Range: start " + start + " , count " + count);
  365.     }
  366.     /**
  367.      * private functions
  368.      */
  369.     /**
  370.       * Expanded takes the array back to a 65536 element array
  371.       */
  372.     private void expand()
  373.     {
  374.         int i;
  375.         if (isCompact) {
  376.             char[]  tempArray;
  377.             tempArray = new char[UNICODECOUNT];
  378.             for (i = 0; i < UNICODECOUNT; ++i) {
  379.                 tempArray[i] =(values[((int)indices[i>>BLOCKSHIFT] & 0xFFFF) +
  380.                                      (i & BLOCKMASK)]);;
  381.             }
  382.             for (i = 0; i < INDEXCOUNT; ++i) {
  383.                 indices[i] = (short)(i<<BLOCKSHIFT);
  384.             }
  385.             values = null;
  386.             values = tempArray;
  387.             isCompact = false;
  388.         }
  389.     }
  390.     // # of elements in the indexed array
  391.     private short capacity()
  392.     {
  393.         return (short)values.length;
  394.     }
  395.     private char getArrayValue(int n)
  396.     {
  397.         return values[n];
  398.     }
  399.     private short getIndexArrayValue(int n)
  400.     {
  401.         return indices[n];
  402.     }
  403.     private int
  404.     FindOverlappingPosition(int start, char[] tempIndex, int tempIndexCount)
  405.     {
  406.         int i;
  407.         short j;
  408.         short currentCount;
  409.  
  410.         if (DEBUGOVERLAP && start < DEBUGSHOWOVERLAPLIMIT) {
  411.             printPlainArray(start, BLOCKCOUNT, null);
  412.             printPlainArray(0, tempIndexCount, tempIndex);
  413.         }
  414.         for (i = 0; i < tempIndexCount; i += BLOCKCOUNT) {
  415.             currentCount = (short)BLOCKCOUNT;
  416.             if (i + BLOCKCOUNT > tempIndexCount) {
  417.                 currentCount = (short)(tempIndexCount - i);
  418.             }
  419.             for (j = 0; j < currentCount; ++j) {
  420.                 if (values[start + j] != values[tempIndex[i + j]]) break;
  421.             }
  422.             if (j == currentCount) break;
  423.         }
  424.         if (DEBUGOVERLAP && start < DEBUGSHOWOVERLAPLIMIT) {
  425.             for (j = 1; j < i; ++j) {
  426.                 System.out.print(" ");
  427.             }
  428.             printPlainArray(start, BLOCKCOUNT, null);
  429.             System.out.println("    Found At: " + i);
  430.         }
  431.         return i;
  432.     }
  433.  
  434.     private static  final int DEBUGSHOWOVERLAPLIMIT = 100;
  435.     private static  final boolean DEBUGTRACE = false;
  436.     private static  final boolean DEBUGSMALL = false;
  437.     private static  final boolean DEBUGOVERLAP = false;
  438.     private static  final int DEBUGSMALLLIMIT = 30000;
  439.     private static  final int BLOCKSHIFT =7;
  440.     private static  final int BLOCKCOUNT =(1<<BLOCKSHIFT);
  441.     private static  final int INDEXSHIFT =(16-BLOCKSHIFT);
  442.     private static  final int INDEXCOUNT =(1<<INDEXSHIFT);
  443.     private static  final int BLOCKMASK = BLOCKCOUNT - 1;
  444.  
  445.     private char[] values;  // char -> short (char parameterized short)
  446.     private short indices[];
  447.     private StringBuffer exceptions = new StringBuffer();
  448.     private boolean isCompact;
  449. };
  450.