source: branches/0.22.x/abcl/src/org/armedbear/lisp/SymbolHashTable.java

Last change on this file was 12298, checked in by ehuelsmann, 15 years ago

Full source scan of "catch (Throwable";

remove lots of instances, or make the catch statement more
specific, e.g. replace Throwable by IOException.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
1/*
2 * SymbolHashTable.java
3 *
4 * Copyright (C) 2004-2005 Peter Graves
5 * $Id: SymbolHashTable.java 12298 2009-12-18 21:50:54Z ehuelsmann $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.util.ArrayList;
37import java.util.List;
38
39public final class SymbolHashTable
40{
41    private static final float LOAD_FACTOR = 0.75f;
42
43    private int threshold;
44    private HashEntry[] buckets;
45    private int count;
46
47    private int mask;
48
49    public SymbolHashTable(int size)
50    {
51        buckets = new HashEntry[calculateInitialCapacity(size)];
52        threshold = (int) (size * LOAD_FACTOR);
53        mask = buckets.length - 1;
54    }
55
56    private static int calculateInitialCapacity(int size)
57    {
58        int capacity = 1;
59        while (capacity < size)
60            capacity <<= 1;
61        return capacity;
62    }
63
64    public Symbol get(SimpleString key)
65    {
66        HashEntry e = buckets[key.sxhash() & mask];
67        while (e != null) {
68            if (key.equal(e.symbol.name))
69                return e.symbol; // Return the symbol.
70            e = e.next;
71        }
72        return null;
73    }
74
75    public Symbol get(SimpleString key, int hash)
76    {
77        HashEntry e = buckets[hash & mask];
78        while (e != null) {
79            if (key.equal(e.symbol.name))
80                return e.symbol; // Return the symbol.
81            e = e.next;
82        }
83        return null;
84    }
85
86    public void put(final SimpleString key, final Symbol symbol)
87    {
88        int index = key.sxhash() & mask;
89        HashEntry e = buckets[index];
90        while (e != null) {
91            if (key.equal(e.symbol.name)) {
92                if (e.symbol != symbol) {
93                    Debug.trace("replacing existing key for " + key.getStringValue() +
94                                " in package " + e.symbol.getPackage().writeToString());
95                    Thread.dumpStack();
96                    e.symbol = symbol;
97                }
98                return;
99            }
100            e = e.next;
101        }
102        // Not found. We need to add a new entry.
103        if (++count > threshold) {
104            rehash();
105            // We need a new index for the bigger table.
106            index = key.sxhash() & mask;
107        }
108        e = new HashEntry(symbol);
109        e.next = buckets[index];
110        buckets[index] = e;
111    }
112
113    public void put(Symbol symbol)
114    {
115        int index = symbol.sxhash() & mask;
116        HashEntry e = buckets[index];
117        while (e != null) {
118            if (symbol.name.equal(e.symbol.name)) {
119                if (e.symbol != symbol) {
120                    Debug.trace("replacing existing key for " + symbol.getName());
121                    Thread.dumpStack();
122                    e.symbol = symbol; // Replace existing key.
123                }
124                return;
125            }
126            e = e.next;
127        }
128        // Not found. We need to add a new entry.
129        if (++count > threshold) {
130            rehash();
131            // Need a new hash value to suit the bigger table.
132            index = symbol.sxhash() & mask;
133        }
134        e = new HashEntry(symbol);
135        e.next = buckets[index];
136        buckets[index] = e;
137    }
138
139    public LispObject remove(LispObject key)
140    {
141        if (key instanceof Symbol)
142            key = ((Symbol)key).name;
143        int index = key.sxhash() & mask;
144        HashEntry e = buckets[index];
145        HashEntry last = null;
146        while (e != null) {
147            if (key.equal(e.symbol.name)) {
148                if (last == null)
149                    buckets[index] = e.next;
150                else
151                    last.next = e.next;
152                --count;
153                return e.symbol; // The key is the value!
154            }
155            last = e;
156            e = e.next;
157        }
158        return null;
159    }
160
161    private void rehash()
162    {
163        HashEntry[] oldBuckets = buckets;
164        int newCapacity = buckets.length * 2;
165        threshold = (int) (newCapacity * LOAD_FACTOR);
166        buckets = new HashEntry[newCapacity];
167        mask = buckets.length - 1;
168        for (int i = oldBuckets.length; i-- > 0;) {
169            HashEntry e = oldBuckets[i];
170            while (e != null) {
171                final int index = e.symbol.sxhash() & mask;
172                HashEntry dest = buckets[index];
173                if (dest != null) {
174                    while (dest.next != null)
175                        dest = dest.next;
176                    dest.next = e;
177                } else
178                    buckets[index] = e;
179                HashEntry next = e.next;
180                e.next = null;
181                e = next;
182            }
183        }
184    }
185
186    public List<Symbol> getSymbols()
187    {
188        ArrayList<Symbol> list = new ArrayList<Symbol>();
189        for (int i = 0; i < buckets.length; i++) {
190            HashEntry e = buckets[i];
191            while (e != null) {
192                list.add(e.symbol);
193                e = e.next;
194            }
195        }
196        return list;
197    }
198
199    private static class HashEntry
200    {
201        Symbol symbol;
202        HashEntry next;
203
204        HashEntry(Symbol symbol)
205        {
206            this.symbol = symbol;
207        }
208    }
209}
Note: See TracBrowser for help on using the repository browser.