• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006 The Android Open Source Project
2 
3 #ifndef HASH_TABLE_H
4 #define HASH_TABLE_H
5 
6 #include <string.h>
7 #include <inttypes.h>
8 
9 template<class T>
10 class HashTable {
11   public:
12     HashTable(int size, T default_value = T());
13     ~HashTable();
14 
15     typedef struct entry {
16         entry    *next;
17         char     *key;
18         T        value;
19     } entry_type;
20 
21     typedef T value_type;
22 
23     void         Update(const char *key, T value);
24     bool         Remove(const char *key);
25     T            Find(const char *key);
26     entry_type*  GetFirst();
27     entry_type*  GetNext();
28 
29   private:
30     uint32_t     HashFunction(const char *key);
31 
32     int          size_;
33     int          mask_;
34     T            default_value_;
35     entry_type   **table_;
36     int          num_entries_;
37     int          current_index_;
38     entry_type   *current_ptr_;
39 };
40 
41 template<class T>
HashTable(int size,T default_value)42 HashTable<T>::HashTable(int size, T default_value)
43 {
44     int pow2;
45 
46     // Round up size to a power of two
47     for (pow2 = 2; pow2 < size; pow2 <<= 1)
48         ;    // empty body
49 
50     size_ = pow2;
51     mask_ = pow2 - 1;
52     default_value_ = default_value;
53 
54     // Allocate a table of pointers and initialize them all to NULL.
55     table_ = new entry_type*[size_];
56     for (int ii = 0; ii < size_; ++ii)
57         table_[ii] = NULL;
58     num_entries_ = 0;
59     current_index_ = 0;
60     current_ptr_ = NULL;
61 }
62 
63 template<class T>
~HashTable()64 HashTable<T>::~HashTable()
65 {
66     for (int ii = 0; ii < size_; ++ii) {
67         entry_type *ptr, *next;
68 
69         // Delete all the pointers in the chain at this table position.
70         // Save the next pointer before deleting each entry so that we
71         // don't dereference part of a deallocated object.
72         for (ptr = table_[ii]; ptr; ptr = next) {
73             next = ptr->next;
74             delete[] ptr->key;
75             delete ptr;
76         }
77     }
78     delete[] table_;
79 }
80 
81 // Professor Daniel J. Bernstein's hash function.  See
82 // http://www.partow.net/programming/hashfunctions/
83 template<class T>
HashFunction(const char * key)84 uint32_t HashTable<T>::HashFunction(const char *key)
85 {
86     uint32_t hash = 5381;
87 
88     int len = strlen(key);
89     for(int ii = 0; ii < len; ++key, ++ii)
90         hash = ((hash << 5) + hash) + *key;
91 
92     return hash;
93 }
94 
95 template<class T>
Update(const char * key,T value)96 void HashTable<T>::Update(const char *key, T value)
97 {
98     // Hash the key to get the table position
99     int len = strlen(key);
100     int pos = HashFunction(key) & mask_;
101 
102     // Search the chain for a matching key
103     for (entry_type *ptr = table_[pos]; ptr; ptr = ptr->next) {
104         if (strcmp(ptr->key, key) == 0) {
105             ptr->value = value;
106             return;
107         }
108     }
109 
110     // Create a new hash entry and fill in the values
111     entry_type *ptr = new entry_type;
112 
113     // Copy the string
114     ptr->key = new char[len + 1];
115     strcpy(ptr->key, key);
116     ptr->value = value;
117 
118     // Insert the new entry at the beginning of the list
119     ptr->next = table_[pos];
120     table_[pos] = ptr;
121     num_entries_ += 1;
122 }
123 
124 template<class T>
Remove(const char * key)125 bool HashTable<T>::Remove(const char *key)
126 {
127     // Hash the key to get the table position
128     int len = strlen(key);
129     int pos = HashFunction(key) & mask_;
130 
131     // Search the chain for a matching key and keep track of the previous
132     // element in the chain.
133     entry_type *prev = NULL;
134     for (entry_type *ptr = table_[pos]; ptr; prev = ptr, ptr = ptr->next) {
135         if (strcmp(ptr->key, key) == 0) {
136             if (prev == NULL) {
137                 table_[pos] = ptr->next;
138             } else {
139                 prev->next = ptr->next;
140             }
141             delete ptr->key;
142             delete ptr;
143             return true;
144         }
145     }
146     return false;
147 }
148 
149 template<class T>
Find(const char * key)150 typename HashTable<T>::value_type HashTable<T>::Find(const char *key)
151 {
152     // Hash the key to get the table position
153     int pos = HashFunction(key) & mask_;
154 
155     // Search the chain for a matching key
156     for (entry_type *ptr = table_[pos]; ptr; ptr = ptr->next) {
157         if (strcmp(ptr->key, key) == 0)
158             return ptr->value;
159     }
160 
161     // If we get here, then we didn't find the key
162     return default_value_;
163 }
164 
165 template<class T>
GetFirst()166 typename HashTable<T>::entry_type* HashTable<T>::GetFirst()
167 {
168     // Find the first non-NULL table entry.
169     for (current_index_ = 0; current_index_ < size_; ++current_index_) {
170         if (table_[current_index_])
171             break;
172     }
173 
174     // If there are no table entries, then return NULL.
175     if (current_index_ == size_)
176         return NULL;
177 
178     // Remember and return the current element.
179     current_ptr_ = table_[current_index_];
180     return current_ptr_;
181 }
182 
183 template<class T>
GetNext()184 typename HashTable<T>::entry_type* HashTable<T>::GetNext()
185 {
186     // If we already iterated part way through the hash table, then continue
187     // to the next element.
188     if (current_ptr_) {
189         current_ptr_ = current_ptr_->next;
190 
191         // If we are pointing to a valid element, then return it.
192         if (current_ptr_)
193             return current_ptr_;
194 
195         // Otherwise, start searching at the next table index.
196         current_index_ += 1;
197     }
198 
199     // Find the next non-NULL table entry.
200     for (; current_index_ < size_; ++current_index_) {
201         if (table_[current_index_])
202             break;
203     }
204 
205     // If there are no more non-NULL table entries, then return NULL.
206     if (current_index_ == size_) {
207         // Reset the current index so that we will start over from the
208         // beginning on the next call to GetNext().
209         current_index_ = 0;
210         return NULL;
211     }
212 
213     // Remember and return the current element.
214     current_ptr_ = table_[current_index_];
215     return current_ptr_;
216 }
217 
218 
219 #endif  // HASH_TABLE_H
220