001 /*
002 * Copyright 1999-2008 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 com.sun.tools.javac.util;
027
028 import java.lang.ref.WeakReference;
029
030 /**
031 * Implementation of Name.Table that stores names in individual arrays
032 * using weak references. It is recommended for use when a single shared
033 * byte array is unsuitable.
034 *
035 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
036 * you write code that depends on this, you do so at your own risk.
037 * This code and its internal interfaces are subject to change or
038 * deletion without notice.</b>
039 */
040 public class UnsharedNameTable extends Name.Table {
041 static public Name.Table create(Names names) {
042 return new UnsharedNameTable(names);
043 }
044
045 static class HashEntry extends WeakReference<NameImpl> {
046 HashEntry next;
047 HashEntry(NameImpl referent) {
048 super(referent);
049 }
050 }
051
052 /** The hash table for names.
053 */
054 private HashEntry[] hashes = null;
055
056 /** The mask to be used for hashing
057 */
058 private int hashMask;
059
060 /** Index counter for names in this table.
061 */
062 public int index;
063
064 /** Allocator
065 * @param names The main name table
066 * @param hashSize the (constant) size to be used for the hash table
067 * needs to be a power of two.
068 */
069 public UnsharedNameTable(Names names, int hashSize) {
070 super(names);
071 hashMask = hashSize - 1;
072 hashes = new HashEntry[hashSize];
073 }
074
075 public UnsharedNameTable(Names names) {
076 this(names, 0x8000);
077 }
078
079
080 @Override
081 public Name fromChars(char[] cs, int start, int len) {
082 byte[] name = new byte[len * 3];
083 int nbytes = Convert.chars2utf(cs, start, name, 0, len);
084 return fromUtf(name, 0, nbytes);
085 }
086
087 @Override
088 public Name fromUtf(byte[] cs, int start, int len) {
089 int h = hashValue(cs, start, len) & hashMask;
090
091 HashEntry element = hashes[h];
092
093 NameImpl n = null;
094
095 HashEntry previousNonNullTableEntry = null;
096 HashEntry firstTableEntry = element;
097
098 while (element != null) {
099 if (element == null) {
100 break;
101 }
102
103 n = element.get();
104
105 if (n == null) {
106 if (firstTableEntry == element) {
107 hashes[h] = firstTableEntry = element.next;
108 }
109 else {
110 assert previousNonNullTableEntry != null : "previousNonNullTableEntry cannot be null here.";
111 previousNonNullTableEntry.next = element.next;
112 }
113 }
114 else {
115 if (n.getByteLength() == len && equals(n.bytes, 0, cs, start, len)) {
116 return n;
117 }
118 previousNonNullTableEntry = element;
119 }
120
121 element = element.next;
122 }
123
124 byte[] bytes = new byte[len];
125 System.arraycopy(cs, start, bytes, 0, len);
126 n = new NameImpl(this, bytes, index++);
127
128 System.arraycopy(cs, start, n.bytes, 0, len);
129
130 HashEntry newEntry = new HashEntry(n);
131
132 if (previousNonNullTableEntry == null) { // We are not the first name with that hashCode.
133 hashes[h] = newEntry;
134 }
135 else {
136 assert previousNonNullTableEntry.next == null : "previousNonNullTableEntry.next must be null.";
137 previousNonNullTableEntry.next = newEntry;
138 }
139
140 return n;
141 }
142
143 @Override
144 public void dispose() {
145 hashes = null;
146 }
147
148 static class NameImpl extends Name {
149 NameImpl(UnsharedNameTable table, byte[] bytes, int index) {
150 super(table);
151 this.bytes = bytes;
152 this.index = index;
153 }
154
155 final byte[] bytes;
156 final int index;
157
158 @Override
159 public int getIndex() {
160 return index;
161 }
162
163 @Override
164 public int getByteLength() {
165 return bytes.length;
166 }
167
168 @Override
169 public byte getByteAt(int i) {
170 return bytes[i];
171 }
172
173 @Override
174 public byte[] getByteArray() {
175 return bytes;
176 }
177
178 @Override
179 public int getByteOffset() {
180 return 0;
181 }
182
183 }
184
185 }