1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package org.openjdk.buildtools.generatebreakiteratordata;
  27 
  28 import java.util.Arrays;
  29 
  30 final class SupplementaryCharacterData {
  31 
  32     /**
  33      * Default value
  34      */
  35     private static final byte DEFAULT_VALUE = 0;
  36     private byte defaultValue;
  37 
  38     /**
  39      * A array which has a unicode code point(0x010000-0x10FFFF) as the upper
  40      * 3 bytes and a value as the remaining one byte in each data.
  41      */
  42     private int[] dataTable;
  43 
  44     /*
  45      * Counter to keep the number of data in tempTable
  46      */
  47     private int dataCount;
  48 
  49     /*
  50      * Temporary data table used until dataTable is generated.
  51      */
  52     private long[] tempTable;
  53 
  54     /*
  55      * Initila tempTable size
  56      */
  57     private static final int INITIAL_TABLE_SIZE = 150;
  58 
  59     /*
  60      * The number of entries to be appended when tempTable becomes full
  61      */
  62     private static final int ADDITIONAL_TABLE_SIZE = 10;
  63 
  64     /*
  65      * Upper limit, used as a sentinel
  66      */
  67     private static final int UPPER_LIMIT = Character.MAX_CODE_POINT + 1;
  68 
  69     /*
  70      * Mask for supplementary code points(0x010000-0x10FFFF)
  71      */
  72     private static final int CODEPOINT_MASK = 0x1FFFFF;
  73 
  74 
  75     public SupplementaryCharacterData(byte value) {
  76         defaultValue = value;
  77         dataCount = 0;
  78     }
  79 
  80     /**
  81      * Appends the given data to tempTable
  82      */
  83     public void appendElement(int start, int end, byte value) {
  84         if (tempTable == null) {
  85             tempTable = new long[INITIAL_TABLE_SIZE];
  86         }
  87 
  88         if (dataCount == tempTable.length) {
  89             long[] tempTempTable = new long[dataCount + ADDITIONAL_TABLE_SIZE];
  90             System.arraycopy(tempTable, 0, tempTempTable, 0, dataCount);
  91             tempTable = tempTempTable;
  92         }
  93         tempTable[dataCount++] = ((((long)start<<24) + end)<<8) + value;
  94     }
  95 
  96     /**
  97      * Returns the data table
  98      */
  99     public int[] getArray() {
 100         return dataTable;
 101     }
 102 
 103     /**
 104      * Creates dataTable
 105      */
 106     public void complete() {
 107         dataTable = generateTable();
 108     }
 109 
 110     /**
 111      * Generates a table from the given data
 112      */
 113     private int[] generateTable() {
 114         /* If tempTable is empty, put two data */
 115         if (dataCount == 0) {
 116             int[] tmpArray = new int[2];
 117             tmpArray[0] = composeEntry(0, DEFAULT_VALUE);
 118             tmpArray[1] = composeEntry(UPPER_LIMIT, DEFAULT_VALUE);
 119             tempTable = null;
 120             return tmpArray;
 121         }
 122 
 123         Arrays.sort(tempTable, 0, dataCount);
 124 
 125         int[] newTempTable = new int[dataCount*2 + 3];
 126 
 127         int old_index = 0;
 128         int new_index = 0;
 129         int loop_count = dataCount - 1;
 130         long data = tempTable[old_index];
 131         int start = (int)(data>>32) & CODEPOINT_MASK;
 132         int end   = (int)(data>>8) & CODEPOINT_MASK;
 133 
 134         /*
 135          * Add an entry if the first start code point in tempTable is not
 136          * the minimum supplementary code point.
 137          */
 138         if (start != Character.MIN_SUPPLEMENTARY_CODE_POINT) {
 139             newTempTable[new_index++] = composeEntry(Character.MIN_SUPPLEMENTARY_CODE_POINT, defaultValue);
 140         }
 141 
 142         newTempTable[new_index++] = composeEntry(start, (int)data);
 143         for (int i = 0; i < loop_count; i++) {
 144             data = tempTable[++old_index];
 145             int nextStart = (int)(data>>32) & CODEPOINT_MASK;
 146 
 147             /*
 148              * If the previous end code point is not equal to the previous start
 149              * code point and is not consecutive with the next start code point,
 150              * insert a filler entry before an entry for the next start code
 151              * point.
 152              */
 153             if (end != start && end != nextStart-1) {
 154                 newTempTable[new_index++] = composeEntry(end + 1, defaultValue);
 155             }
 156             newTempTable[new_index++] = composeEntry(nextStart, (int)data);
 157             start = nextStart;
 158             end = (int)(data>>8) & CODEPOINT_MASK;
 159         }
 160         newTempTable[new_index++] = composeEntry(++end, defaultValue);
 161 
 162         /* Add an entry for a sentinel if necessary. */
 163         if (end < UPPER_LIMIT) {
 164             newTempTable[new_index++] = composeEntry(UPPER_LIMIT, defaultValue);
 165         }
 166 
 167         /* Copy data to dataTable. */
 168         dataTable = new int[new_index];
 169         System.arraycopy(newTempTable, 0, dataTable, 0, new_index);
 170 
 171         tempTable = null;
 172 
 173         return dataTable;
 174     }
 175 
 176     /**
 177      * Composes an entry with the given supplementary code point
 178      * (0x010000-0x10FFFF) for the upper 3 bytes and the given value for the
 179      * remaining one byte.
 180      */
 181     private int composeEntry(int codePoint, int value) {
 182         return (codePoint<<8) | (value&0xFF);
 183     }
 184 }