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    }