~ubuntu-branches/ubuntu/karmic/libxerces2-java/karmic

« back to all changes in this revision

Viewing changes to src/org/apache/xerces/util/SymbolTable.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-04 17:37:55 UTC
  • mfrom: (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20061204173755-hb6ybrrrk097zhx7
Tags: 2.8.1-1ubuntu1
* Merge with Debian unstable; remaining changes:
  - Build -gcj package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * The Apache Software License, Version 1.1
3
 
 *
4
 
 *
5
 
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
6
 
 * reserved.
7
 
 *
8
 
 * Redistribution and use in source and binary forms, with or without
9
 
 * modification, are permitted provided that the following conditions
10
 
 * are met:
11
 
 *
12
 
 * 1. Redistributions of source code must retain the above copyright
13
 
 *    notice, this list of conditions and the following disclaimer.
14
 
 *
15
 
 * 2. Redistributions in binary form must reproduce the above copyright
16
 
 *    notice, this list of conditions and the following disclaimer in
17
 
 *    the documentation and/or other materials provided with the
18
 
 *    distribution.
19
 
 *
20
 
 * 3. The end-user documentation included with the redistribution,
21
 
 *    if any, must include the following acknowledgment:
22
 
 *       "This product includes software developed by the
23
 
 *        Apache Software Foundation (http://www.apache.org/)."
24
 
 *    Alternately, this acknowledgment may appear in the software itself,
25
 
 *    if and wherever such third-party acknowledgments normally appear.
26
 
 *
27
 
 * 4. The names "Xerces" and "Apache Software Foundation" must
28
 
 *    not be used to endorse or promote products derived from this
29
 
 *    software without prior written permission. For written
30
 
 *    permission, please contact apache@apache.org.
31
 
 *
32
 
 * 5. Products derived from this software may not be called "Apache",
33
 
 *    nor may "Apache" appear in their name, without prior written
34
 
 *    permission of the Apache Software Foundation.
35
 
 *
36
 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
 
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
 
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
 
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
 
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
 
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47
 
 * SUCH DAMAGE.
48
 
 * ====================================================================
49
 
 *
50
 
 * This software consists of voluntary contributions made by many
51
 
 * individuals on behalf of the Apache Software Foundation and was
52
 
 * originally based on software copyright (c) 1999, International
53
 
 * Business Machines, Inc., http://www.apache.org.  For more
54
 
 * information on the Apache Software Foundation, please see
55
 
 * <http://www.apache.org/>.
 
2
 * Copyright 2000-2002,2004,2005 The Apache Software Foundation.
 
3
 * 
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 * 
 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
 
9
 * 
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
56
15
 */
57
16
 
58
17
package org.apache.xerces.util;
79
38
 *   characters are especially prone to this poor hashing behavior.
80
39
 *  </li>
81
40
 * </ul>
82
 
 *
 
41
 * 
 
42
 * An instance of <code>SymbolTable</code> has two parameters that affect its
 
43
 * performance: <i>initial capacity</i> and <i>load factor</i>.  The
 
44
 * <i>capacity</i> is the number of <i>buckets</i> in the SymbolTable, and the
 
45
 * <i>initial capacity</i> is simply the capacity at the time the SymbolTable
 
46
 * is created.  Note that the SymbolTable is <i>open</i>: in the case of a "hash
 
47
 * collision", a single bucket stores multiple entries, which must be searched
 
48
 * sequentially.  The <i>load factor</i> is a measure of how full the SymbolTable
 
49
 * is allowed to get before its capacity is automatically increased.
 
50
 * When the number of entries in the SymbolTable exceeds the product of the load
 
51
 * factor and the current capacity, the capacity is increased by calling the
 
52
 * <code>rehash</code> method.<p>
 
53
 *
 
54
 * Generally, the default load factor (.75) offers a good tradeoff between
 
55
 * time and space costs.  Higher values decrease the space overhead but
 
56
 * increase the time cost to look up an entry (which is reflected in most
 
57
 * <tt>SymbolTable</tt> operations, including <tt>addSymbol</tt> and <tt>containsSymbol</tt>).<p>
 
58
 *
 
59
 * The initial capacity controls a tradeoff between wasted space and the
 
60
 * need for <code>rehash</code> operations, which are time-consuming.
 
61
 * No <code>rehash</code> operations will <i>ever</i> occur if the initial
 
62
 * capacity is greater than the maximum number of entries the
 
63
 * <tt>Hashtable</tt> will contain divided by its load factor.  However,
 
64
 * setting the initial capacity too high can waste space.<p>
 
65
 *
 
66
 * If many entries are to be made into a <code>SymbolTable</code>, 
 
67
 * creating it with a sufficiently large capacity may allow the 
 
68
 * entries to be inserted more efficiently than letting it perform 
 
69
 * automatic rehashing as needed to grow the table. <p>
 
70
 
83
71
 * @see SymbolHash
84
72
 *
85
73
 * @author Andy Clark
 
74
 * @author John Kim, IBM
86
75
 *
87
 
 * @version $Id: SymbolTable.java,v 1.7 2002/02/07 22:15:09 neilg Exp $
 
76
 * @version $Id: SymbolTable.java 320244 2005-03-14 23:09:35Z mrglavas $
88
77
 */
89
78
public class SymbolTable {
90
79
 
102
91
    /** Buckets. */
103
92
    protected Entry[] fBuckets = null;
104
93
 
105
 
    // actual table size
 
94
    /** actual table size **/
106
95
    protected int fTableSize;
107
96
 
 
97
    /** The total number of entries in the hash table. */
 
98
    protected transient int fCount;
 
99
 
 
100
    /** The table is rehashed when its size exceeds this threshold.  (The
 
101
     * value of this field is (int)(capacity * loadFactor).) */
 
102
    protected int fThreshold;
 
103
                                                         
 
104
    /** The load factor for the SymbolTable. */
 
105
    protected float fLoadFactor;
 
106
 
108
107
    //
109
108
    // Constructors
110
109
    //
 
110
    
 
111
    /**
 
112
     * Constructs a new, empty SymbolTable with the specified initial 
 
113
     * capacity and the specified load factor.
 
114
     *
 
115
     * @param      initialCapacity   the initial capacity of the SymbolTable.
 
116
     * @param      loadFactor        the load factor of the SymbolTable.
 
117
     * @throws     IllegalArgumentException  if the initial capacity is less
 
118
     *             than zero, or if the load factor is nonpositive.
 
119
     */
 
120
    public SymbolTable(int initialCapacity, float loadFactor) {
 
121
        
 
122
        if (initialCapacity < 0) {
 
123
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
 
124
        }
 
125
        
 
126
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
 
127
            throw new IllegalArgumentException("Illegal Load: " + loadFactor);
 
128
        }
 
129
        
 
130
        if (initialCapacity == 0) {
 
131
            initialCapacity = 1;
 
132
        }
 
133
        
 
134
        fLoadFactor = loadFactor;
 
135
        fTableSize = initialCapacity;
 
136
        fBuckets = new Entry[fTableSize];
 
137
        fThreshold = (int)(fTableSize * loadFactor);
 
138
        fCount = 0;
 
139
    }
111
140
 
112
 
    /** Constructs a symbol table with a default number of buckets. */
 
141
    /**
 
142
     * Constructs a new, empty SymbolTable with the specified initial capacity
 
143
     * and default load factor, which is <tt>0.75</tt>.
 
144
     *
 
145
     * @param     initialCapacity   the initial capacity of the hashtable.
 
146
     * @throws    IllegalArgumentException if the initial capacity is less
 
147
     *            than zero.
 
148
     */
 
149
    public SymbolTable(int initialCapacity) {
 
150
        this(initialCapacity, 0.75f);
 
151
    }
 
152
    
 
153
    /**
 
154
     * Constructs a new, empty SymbolTable with a default initial capacity (101)
 
155
     * and load factor, which is <tt>0.75</tt>. 
 
156
     */
113
157
    public SymbolTable() {
114
 
        this(TABLE_SIZE);
115
 
    }
116
 
 
117
 
    /** Constructs a symbol table with a specified number of buckets. */
118
 
    public SymbolTable(int tableSize) {
119
 
        fTableSize = tableSize;
120
 
        fBuckets = new Entry[fTableSize];
 
158
        this(TABLE_SIZE, 0.75f);
121
159
    }
122
160
 
123
161
    //
133
171
     * @param symbol The new symbol.
134
172
     */
135
173
    public String addSymbol(String symbol) {
136
 
 
 
174
        
137
175
        // search for identical symbol
138
176
        int bucket = hash(symbol) % fTableSize;
139
 
        int length = symbol.length();
140
 
        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
141
 
            if (length == entry.characters.length) {
142
 
                for (int i = 0; i < length; i++) {
143
 
                    if (symbol.charAt(i) != entry.characters[i]) {
144
 
                        continue OUTER;
145
 
                    }
146
 
                }
 
177
        for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
 
178
            if (entry.symbol.equals(symbol)) {
147
179
                return entry.symbol;
148
180
            }
149
181
        }
150
 
 
 
182
        
 
183
        if (fCount >= fThreshold) {
 
184
            // Rehash the table if the threshold is exceeded
 
185
            rehash();
 
186
            bucket = hash(symbol) % fTableSize;
 
187
        } 
 
188
        
151
189
        // create new entry
152
190
        Entry entry = new Entry(symbol, fBuckets[bucket]);
153
191
        fBuckets[bucket] = entry;
 
192
        ++fCount;
154
193
        return entry.symbol;
155
 
 
 
194
        
156
195
    } // addSymbol(String):String
157
196
 
158
197
    /**
166
205
     * @param length The length of the new symbol in the buffer.
167
206
     */
168
207
    public String addSymbol(char[] buffer, int offset, int length) {
169
 
 
 
208
        
170
209
        // search for identical symbol
171
210
        int bucket = hash(buffer, offset, length) % fTableSize;
172
211
        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
179
218
                return entry.symbol;
180
219
            }
181
220
        }
182
 
 
 
221
        
 
222
        if (fCount >= fThreshold) {
 
223
            // Rehash the table if the threshold is exceeded
 
224
            rehash();
 
225
            bucket = hash(buffer, offset, length) % fTableSize;
 
226
        } 
 
227
        
183
228
        // add new entry
184
229
        Entry entry = new Entry(buffer, offset, length, fBuckets[bucket]);
185
230
        fBuckets[bucket] = entry;
 
231
        ++fCount;
186
232
        return entry.symbol;
187
 
 
 
233
        
188
234
    } // addSymbol(char[],int,int):String
189
235
 
190
236
    /**
196
242
     * @param symbol The symbol to hash.
197
243
     */
198
244
    public int hash(String symbol) {
199
 
 
200
 
        int code = 0;
201
 
        int length = symbol.length();
202
 
        for (int i = 0; i < length; i++) {
203
 
            code = code * 37 + symbol.charAt(i);
204
 
        }
205
 
        return code & 0x7FFFFFF;
206
 
 
 
245
        return symbol.hashCode() & 0x7FFFFFF;
207
246
    } // hash(String):int
208
247
 
209
248
    /**
220
259
    public int hash(char[] buffer, int offset, int length) {
221
260
 
222
261
        int code = 0;
223
 
        for (int i = 0; i < length; i++) {
224
 
            code = code * 37 + buffer[offset + i];
 
262
        for (int i = 0; i < length; ++i) {
 
263
            code = code * 31 + buffer[offset + i];
225
264
        }
226
265
        return code & 0x7FFFFFF;
227
266
 
228
267
    } // hash(char[],int,int):int
229
268
 
230
269
    /**
 
270
     * Increases the capacity of and internally reorganizes this 
 
271
     * SymbolTable, in order to accommodate and access its entries more 
 
272
     * efficiently.  This method is called automatically when the 
 
273
     * number of keys in the SymbolTable exceeds this hashtable's capacity 
 
274
     * and load factor. 
 
275
     */
 
276
    protected void rehash() {
 
277
 
 
278
        int oldCapacity = fBuckets.length;
 
279
        Entry[] oldTable = fBuckets;
 
280
 
 
281
        int newCapacity = oldCapacity * 2 + 1;
 
282
        Entry[] newTable = new Entry[newCapacity];
 
283
 
 
284
        fThreshold = (int)(newCapacity * fLoadFactor);
 
285
        fBuckets = newTable;
 
286
        fTableSize = fBuckets.length;
 
287
 
 
288
        for (int i = oldCapacity ; i-- > 0 ;) {
 
289
            for (Entry old = oldTable[i] ; old != null ; ) {
 
290
                Entry e = old;
 
291
                old = old.next;
 
292
 
 
293
                int index = hash(e.characters, 0, e.characters.length) % newCapacity;
 
294
                e.next = newTable[index];
 
295
                newTable[index] = e;
 
296
            }
 
297
        }
 
298
    }
 
299
 
 
300
    /**
231
301
     * Returns true if the symbol table already contains the specified
232
302
     * symbol.
233
303
     *