1 /*
2  * Copyright (c) 1996, 2006, 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 #include "Hashtable.h"
27 
Hashtable(const char * name,void (* deleteProc)(void *),int initialCapacity,float loadFactor)28 Hashtable::Hashtable(const char* name, void (*deleteProc)(void*),
29                      int initialCapacity, float loadFactor) {
30     DASSERT ((initialCapacity > 0) && (loadFactor > 0.0));
31 
32     table = (HashtableEntry**)
33         safe_Calloc(initialCapacity, sizeof(HashtableEntry*));
34 
35     capacity = initialCapacity;
36     count = 0;
37     threshold = (int)(capacity * loadFactor);
38     this->loadFactor = loadFactor;
39     m_deleteProc = deleteProc;
40 
41 #ifdef DEBUG
42     m_name = (char*)name;
43     m_max = 0;
44     m_collisions = 0;
45 #else
46     name;  // suppress "unused parameter" warning
47 #endif
48 }
49 
~Hashtable()50 Hashtable::~Hashtable()
51 {
52 #ifdef DEBUG
53     DTRACE_PRINTLN3("%s: %d entries, %d maximum entries\n", m_name, count, m_max);
54 #endif
55     clear();
56     free(table);
57 }
58 
contains(void * value)59 BOOL Hashtable::contains(void* value) {
60     DASSERT(value != NULL);
61 
62     CriticalSection::Lock l(lock);
63 
64     for (int i = capacity; i-- > 0;) {
65         for (HashtableEntry* e = table[i] ; e != NULL ; e = e->next) {
66             if (e->value == value) {
67                 return TRUE;
68             }
69         }
70     }
71     return FALSE;
72 }
73 
containsKey(void * key)74 BOOL Hashtable::containsKey(void* key) {
75     CriticalSection::Lock l(lock);
76     int index = static_cast<int>(((reinterpret_cast<INT_PTR>(key) << 1) >> 1)
77         % capacity);
78     for (HashtableEntry* e = table[index]; e != NULL; e = e->next) {
79         if (e->hash == (INT_PTR)key && e->key == key) {
80             return TRUE;
81         }
82     }
83     return FALSE;
84 }
85 
get(void * key)86 void* Hashtable::get(void* key) {
87     CriticalSection::Lock l(lock);
88     int index = static_cast<int>(((reinterpret_cast<INT_PTR>(key) << 1) >> 1)
89         % capacity);
90     for (HashtableEntry* e = table[index]; e != NULL; e = e->next) {
91         if (e->hash == (INT_PTR)key && e->key == key) {
92             return e->value;
93         }
94     }
95     return NULL;
96 }
97 
rehash()98 void Hashtable::rehash() {
99     int oldCapacity = capacity;
100     HashtableEntry** oldTable = table;
101 
102     int newCapacity = oldCapacity * 2 + 1;
103     HashtableEntry** newTable = (HashtableEntry**)safe_Calloc(
104         newCapacity, sizeof(HashtableEntry*));
105 
106     threshold = (int)(newCapacity * loadFactor);
107     table = newTable;
108     capacity = newCapacity;
109 
110     for (int i = 0; i < oldCapacity; i++) {
111         for (HashtableEntry* old = oldTable[i] ; old != NULL ; ) {
112             HashtableEntry* e = old;
113             old = old->next;
114             int index = static_cast<int>(((e->hash << 1) >> 1) % newCapacity);
115             e->next = newTable[index];
116             newTable[index] = e;
117         }
118     }
119 
120     free(oldTable);
121 }
122 
put(void * key,void * value)123 void* Hashtable::put(void* key, void* value) {
124     DASSERT(value != NULL);
125     CriticalSection::Lock l(lock);
126     HashtableEntry* e;
127 
128     // Makes sure the key is not already in the hashtable.
129     int index = (int)(((INT_PTR)key << 1) >> 1) % capacity;
130     for (e = table[index]; e != NULL; e = e->next) {
131 #ifdef DEBUG
132         m_collisions++;
133 #endif
134         if (e->hash == (INT_PTR)key && e->key == key) {
135             void* old = e->value;
136             e->value = value;
137             return old;
138         }
139     }
140 
141     if (count >= threshold) {
142         // Rehash the table if the threshold is exceeded
143         rehash();
144         return put(key, value);
145     }
146 
147     // Creates the new entry.
148     e = new HashtableEntry;
149     e->hash = (INT_PTR)key;
150     e->key = key;
151     e->value = value;
152     e->next = table[index];
153     table[index] = e;
154     count++;
155 #ifdef DEBUG
156     if (count > m_max) {
157         m_max = count;
158     }
159 #endif
160     return NULL;
161 }
162 
remove(void * key)163 void* Hashtable::remove(void* key) {
164     CriticalSection::Lock l(lock);
165     int index = (int)(((INT_PTR)key << 1) >> 1) % capacity;
166     HashtableEntry* prev = NULL;
167     for (HashtableEntry* e = table[index]; e != NULL ; prev = e, e = e->next) {
168         if (e->key == key) {
169             void* value = e->value;
170             if (prev != NULL) {
171                 prev->next = e->next;
172             } else {
173                 table[index] = e->next;
174             }
175             count--;
176             delete e;
177             return value;
178         }
179     }
180     return NULL;
181 }
182 
clear()183 void Hashtable::clear() {
184     CriticalSection::Lock l(lock);
185     for (int index = capacity; --index >= 0; ) {
186         HashtableEntry* e = table[index];
187         while (e != NULL) {
188             HashtableEntry* next = e->next;
189             if (m_deleteProc) {
190                 (*m_deleteProc)(e->value);
191             }
192             delete e;
193             e = next;
194         }
195         table[index] = NULL;
196     }
197     count = 0;
198 }
199 
HashtableEnumerator(HashtableEntry * table[],int size,BOOL keys)200 HashtableEnumerator::HashtableEnumerator(HashtableEntry* table[], int size,
201                                          BOOL keys)
202 {
203     this->table = table;
204     this->keys = keys;
205     this->index = size;
206     this->entry = NULL;
207 }
208 
hasMoreElements()209 BOOL HashtableEnumerator::hasMoreElements() {
210     if (entry != NULL) {
211         return TRUE;
212     }
213     while (index-- > 0) {
214         if ((entry = table[index]) != NULL) {
215             return TRUE;
216         }
217     }
218     return FALSE;
219 }
220 
nextElement()221 void* HashtableEnumerator::nextElement() {
222     if (entry == NULL) {
223         while ((index-- > 0) && ((entry = table[index]) == NULL));
224     }
225     if (entry != NULL) {
226         HashtableEntry* e = entry;
227         entry = e->next;
228         return keys ? e->key : e->value;
229     }
230     DASSERT(FALSE);  // shouldn't get here
231     return NULL;
232 }
233