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