• 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