Pyrogenesis  trunk
dyn_hash_tbl.h
Go to the documentation of this file.
1 /* Copyright (c) 2011 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * dynamic (grow-able) hash table
25  */
26 
27 #ifndef INCLUDED_ADTS_DYN_HASH_TBL
28 #define INCLUDED_ADTS_DYN_HASH_TBL
29 
30 #include <string.h> // strcmp
31 
32 #include "lib/fnv_hash.h"
33 
34 template<typename Key, typename T> class DHT_Traits
35 {
36 public:
37  static const size_t initial_entries = 16;
38  size_t hash(Key key) const;
39  bool equal(Key k1, Key k2) const;
40  Key get_key(T t) const;
41 };
42 
43 template<> class DHT_Traits<const char*, const char*>
44 {
45 public:
46  static const size_t initial_entries = 512;
47  size_t hash(const char* key) const
48  {
49  return (size_t)fnv_lc_hash(key);
50  }
51  bool equal(const char* k1, const char* k2) const
52  {
53  return !strcmp(k1, k2);
54  }
55  const char* get_key(const char* t) const
56  {
57  return t;
58  }
59 };
60 
61 
62 // intended for pointer types
63 template<typename Key, typename T, typename Traits=DHT_Traits<Key,T> >
65 {
66  T* tbl;
68  u16 max_entries; // when initialized, = 2**n for faster modulo
69  Traits tr;
70 
71  T& get_slot(Key key) const
72  {
73  size_t hash = tr.hash(key);
74  ENSURE(max_entries != 0); // otherwise, mask will be incorrect
75  const size_t mask = max_entries-1;
76  for(;;)
77  {
78  T& t = tbl[hash & mask];
79  // empty slot encountered => not found
80  if(!t)
81  return t;
82  // keys are actually equal => found it
83  if(tr.equal(key, tr.get_key(t)))
84  return t;
85  // keep going (linear probing)
86  hash++;
87  }
88  }
89 
90  void expand_tbl()
91  {
92  // alloc a new table (but don't assign it to <tbl> unless successful)
93  T* old_tbl = tbl;
94  tbl = (T*)calloc(max_entries*2, sizeof(T));
95  if(!tbl)
96  {
97  tbl = old_tbl;
98  throw std::bad_alloc();
99  }
100 
101  max_entries *= 2;
102  // must be set before get_slot
103 
104  // newly initialized, nothing to copy - done
105  if(!old_tbl)
106  return;
107 
108  // re-hash from old table into the new one
109  for(size_t i = 0; i < max_entries/2u; i++)
110  {
111  T t = old_tbl[i];
112  if(t)
113  get_slot(tr.get_key(t)) = t;
114  }
115  free(old_tbl);
116  }
117 
118 
119 public:
120 
122  {
123  tbl = 0;
124  clear();
125  }
126 
128  {
129  free(tbl);
130  }
131 
132  void clear()
133  {
134  // must remain usable after calling clear, so shrink the table to
135  // its initial size but don't deallocate it completely
136  SAFE_FREE(tbl);
137  num_entries = 0;
138  // rationale: must not set to 0 because expand_tbl only doubles the size.
139  // don't keep the previous size when clearing because it may have become
140  // huge and there is no provision for shrinking.
141  max_entries = tr.initial_entries/2; // will be doubled in expand_tbl
142  expand_tbl();
143  }
144 
145  void insert(const Key key, const T t)
146  {
147  // more than 75% full - increase table size.
148  // do so before determining slot; this will invalidate previous pnodes.
149  if(num_entries*4 >= max_entries*3)
150  expand_tbl();
151 
152  T& slot = get_slot(key);
153  ENSURE(slot == 0); // not already present
154  slot = t;
155  num_entries++;
156  }
157 
158  T find(Key key) const
159  {
160  return get_slot(key);
161  }
162 
163  size_t size() const
164  {
165  return num_entries;
166  }
167 
168 
169  class iterator
170  {
171  public:
172  typedef std::forward_iterator_tag iterator_category;
173  typedef T value_type;
174  typedef ptrdiff_t difference_type;
175  typedef const T* pointer;
176  typedef const T& reference;
177 
179  {
180  }
181  iterator(T* pos_, T* end_) : pos(pos_), end(end_)
182  {
183  }
184  T& operator*() const
185  {
186  return *pos;
187  }
189  {
190  do
191  pos++;
192  while(pos != end && *pos == 0);
193  return (*this);
194  }
195  bool operator==(const iterator& rhs) const
196  {
197  return pos == rhs.pos;
198  }
199  bool operator<(const iterator& rhs) const
200  {
201  return (pos < rhs.pos);
202  }
203 
204  // derived
205  const T* operator->() const
206  {
207  return &**this;
208  }
209  bool operator!=(const iterator& rhs) const
210  {
211  return !(*this == rhs);
212  }
213  iterator operator++(int) // post
214  {
215  iterator tmp = *this; ++*this; return tmp;
216  }
217 
218  protected:
219  T* pos;
220  T* end;
221  // only used when incrementing (avoid going beyond end of table)
222  };
223 
224  iterator begin() const
225  {
226  T* pos = tbl;
227  while(pos != tbl+max_entries && *pos == 0)
228  pos++;
229  return iterator(pos, tbl+max_entries);
230  }
231  iterator end() const
232  {
233  return iterator(tbl+max_entries, 0);
234  }
235 };
236 
237 
238 #endif // #ifndef INCLUDED_ADTS_DYN_HASH_TBL
std::forward_iterator_tag iterator_category
Definition: dyn_hash_tbl.h:172
T * pos
Definition: dyn_hash_tbl.h:219
uint16_t u16
Definition: types.h:38
Key get_key(T t) const
size_t hash(Key key) const
iterator()
Definition: dyn_hash_tbl.h:178
const char * get_key(const char *t) const
Definition: dyn_hash_tbl.h:55
size_t size() const
Definition: dyn_hash_tbl.h:163
void clear()
Definition: dyn_hash_tbl.h:132
ptrdiff_t difference_type
Definition: dyn_hash_tbl.h:174
bool operator==(const iterator &rhs) const
Definition: dyn_hash_tbl.h:195
#define SAFE_FREE(p)
free memory ensuing from malloc and set the pointer to zero (thus making double-frees safe / a no-op)...
Definition: code_generation.h:131
~DynHashTbl()
Definition: dyn_hash_tbl.h:127
bool equal(const char *k1, const char *k2) const
Definition: dyn_hash_tbl.h:51
T & get_slot(Key key) const
Definition: dyn_hash_tbl.h:71
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:287
const T * operator->() const
Definition: dyn_hash_tbl.h:205
size_t hash(const char *key) const
Definition: dyn_hash_tbl.h:47
T find(Key key) const
Definition: dyn_hash_tbl.h:158
void insert(const Key key, const T t)
Definition: dyn_hash_tbl.h:145
pthread_key_t key
Definition: wpthread.cpp:140
T value_type
Definition: dyn_hash_tbl.h:173
T & operator*() const
Definition: dyn_hash_tbl.h:184
#define T(string_literal)
Definition: secure_crt.cpp:76
bool equal(Key k1, Key k2) const
Definition: dyn_hash_tbl.h:169
static const size_t initial_entries
Definition: dyn_hash_tbl.h:37
const T & reference
Definition: dyn_hash_tbl.h:176
iterator end() const
Definition: dyn_hash_tbl.h:231
Definition: dyn_hash_tbl.h:34
Definition: dyn_hash_tbl.h:64
void expand_tbl()
Definition: dyn_hash_tbl.h:90
T * end
Definition: dyn_hash_tbl.h:220
iterator operator++(int)
Definition: dyn_hash_tbl.h:213
bool operator<(const iterator &rhs) const
Definition: dyn_hash_tbl.h:199
iterator begin() const
Definition: dyn_hash_tbl.h:224
iterator(T *pos_, T *end_)
Definition: dyn_hash_tbl.h:181
u16 num_entries
Definition: dyn_hash_tbl.h:67
Traits tr
Definition: dyn_hash_tbl.h:69
u32 fnv_lc_hash(const char *str, size_t len)
special version of fnv_hash for strings: first converts to lowercase (useful for comparing mixed-case...
Definition: fnv_hash.cpp:105
T * tbl
Definition: dyn_hash_tbl.h:66
u16 max_entries
Definition: dyn_hash_tbl.h:68
const T * pointer
Definition: dyn_hash_tbl.h:175
DynHashTbl()
Definition: dyn_hash_tbl.h:121
iterator & operator++()
Definition: dyn_hash_tbl.h:188
bool operator!=(const iterator &rhs) const
Definition: dyn_hash_tbl.h:209