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 }