MFEM  v3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
hash.hpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.googlecode.com.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #ifndef MFEM_HASH
13 #define MFEM_HASH
14 
15 #include "../config/config.hpp"
16 #include "array.hpp"
17 
18 namespace mfem
19 {
20 
26 {
27 public:
28  IdGenerator(int first_id = 0) : next(first_id) {}
29 
31  int Get()
32  {
33  if (reusable.Size())
34  {
35  int id = reusable.Last();
36  reusable.DeleteLast();
37  return id;
38  }
39  return next++;
40  }
41 
43  void Reuse(int id)
44  {
45  reusable.Append(id);
46  }
47 
48 private:
49  int next;
50  Array<int> reusable;
51 };
52 
53 
60 template<typename Derived>
61 struct Hashed2
62 {
63  int id;
64  int p1, p2;
65  Derived* next;
66 
67  Hashed2(int id) : id(id) {}
68 };
69 
73 template<typename Derived>
74 struct Hashed4
75 {
76  int id;
77  int p1, p2, p3; // NOTE: p4 is not hashed nor stored
78  Derived* next;
79 
80  Hashed4(int id) : id(id) {}
81 };
82 
83 
111 template<typename ItemT>
113 {
114 public:
115  HashTable(int init_size = 32*1024);
116  ~HashTable();
117 
119  ItemT* Get(int p1, int p2);
120  ItemT* Get(int p1, int p2, int p3, int p4);
121 
123  ItemT* Peek(int p1, int p2) const;
124  ItemT* Peek(int p1, int p2, int p3, int p4) const;
125 
126  // item pointer variants of the above for convenience
127  template<typename OtherT>
128  ItemT* Get(OtherT* i1, OtherT* i2)
129  { return Get(i1->id, i2->id); }
130 
131  template<typename OtherT>
132  ItemT* Get(OtherT* i1, OtherT* i2, OtherT* i3, OtherT* i4)
133  { return Get(i1->id, i2->id, i3->id, i4->id); }
134 
135  template<typename OtherT>
136  ItemT* Peek(OtherT* i1, OtherT* i2) const
137  { return Peek(i1->id, i2->id); }
138 
139  template<typename OtherT>
140  ItemT* Peek(OtherT* i1, OtherT* i2, OtherT* i3, OtherT* i4) const
141  { return Peek(i1->id, i2->id, i3->id, i4->id); }
142 
144  ItemT* Peek(int id) const { return id_to_item[id]; }
145 
147  void Delete(ItemT* item);
148 
150  void Reparent(ItemT* item, int new_p1, int new_p2);
151  void Reparent(ItemT* item, int new_p1, int new_p2, int new_p3, int new_p4);
152 
154  class Iterator
155  {
156  public:
158  : hash_table(table), cur_id(-1), cur_item(NULL) { next(); }
159 
160  operator ItemT*() const { return cur_item; }
161  ItemT& operator*() const { return *cur_item; }
162  ItemT* operator->() const { return cur_item; }
163 
164  Iterator &operator++() { next(); return *this; }
165 
166  protected:
168  int cur_id;
169  ItemT* cur_item;
170 
171  void next();
172  };
173 
175  long MemoryUsage() const;
176 
177 protected:
178 
179  ItemT** table;
180  int mask;
182 
183  // hash functions (NOTE: the constants are arbitrary)
184  inline int hash(int p1, int p2) const
185  { return (984120265*p1 + 125965121*p2) & mask; }
186 
187  inline int hash(int p1, int p2, int p3) const
188  { return (984120265*p1 + 125965121*p2 + 495698413*p3) & mask; }
189 
190  // Remove() uses one of the following two overloads:
191  inline int hash(const Hashed2<ItemT>* item) const
192  { return hash(item->p1, item->p2); }
193 
194  inline int hash(const Hashed4<ItemT>* item) const
195  { return hash(item->p1, item->p2, item->p3); }
196 
197  ItemT* SearchList(ItemT* item, int p1, int p2) const;
198  ItemT* SearchList(ItemT* item, int p1, int p2, int p3) const;
199 
200  void Insert(int idx, ItemT* item);
201  void Unlink(ItemT* item);
202 
204  void Rehash();
205 
208 };
209 
210 
211 // implementation
212 
213 template<typename ItemT>
215 {
216  mask = init_size-1;
217  if (init_size & mask)
218  mfem_error("HashTable(): init_size size must be a power of two.");
219 
220  table = new ItemT*[init_size];
221  memset(table, 0, init_size * sizeof(ItemT*));
222 
223  num_items = 0;
224 }
225 
226 template<typename ItemT>
228 {
229  // delete all items
230  for (Iterator it(*this); it; ++it)
231  delete it;
232 
233  delete [] table;
234 }
235 
236 namespace internal {
237 
238 inline void sort3(int &a, int &b, int &c)
239 {
240  if (a > b) std::swap(a, b);
241  if (a > c) std::swap(a, c);
242  if (b > c) std::swap(b, c);
243 }
244 
245 inline void sort4(int &a, int &b, int &c, int &d)
246 {
247  if (a > b) std::swap(a, b);
248  if (a > c) std::swap(a, c);
249  if (a > d) std::swap(a, d);
250  sort3(b, c, d);
251 }
252 
253 } // internal
254 
255 template<typename ItemT>
256 ItemT* HashTable<ItemT>::Peek(int p1, int p2) const
257 {
258  if (p1 > p2) std::swap(p1, p2);
259  return SearchList(table[hash(p1, p2)], p1, p2);
260 }
261 
262 template<typename ItemT>
263 ItemT* HashTable<ItemT>::Peek(int p1, int p2, int p3, int p4) const
264 {
265  internal::sort4(p1, p2, p3, p4);
266  return SearchList(table[hash(p1, p2, p3)], p1, p2, p3);
267 }
268 
269 template<typename ItemT>
270 void HashTable<ItemT>::Insert(int idx, ItemT* item)
271 {
272  // insert into hashtable
273  item->next = table[idx];
274  table[idx] = item;
275  num_items++;
276 }
277 
278 template<typename ItemT>
279 ItemT* HashTable<ItemT>::Get(int p1, int p2)
280 {
281  // search for the item in the hashtable
282  if (p1 > p2) std::swap(p1, p2);
283  int idx = hash(p1, p2);
284  ItemT* node = SearchList(table[idx], p1, p2);
285  if (node) return node;
286 
287  // not found - create a new one
288  ItemT* newitem = new ItemT(id_gen.Get());
289  newitem->p1 = p1;
290  newitem->p2 = p2;
291 
292  // insert into hashtable
293  Insert(idx, newitem);
294 
295  // also, maintain the mapping ID -> item
296  if (id_to_item.Size() <= newitem->id) {
297  id_to_item.SetSize(newitem->id + 1, NULL);
298  }
299  id_to_item[newitem->id] = newitem;
300 
301  Rehash();
302  return newitem;
303 }
304 
305 template<typename ItemT>
306 ItemT* HashTable<ItemT>::Get(int p1, int p2, int p3, int p4)
307 {
308  // search for the item in the hashtable
309  internal::sort4(p1, p2, p3, p4);
310  int idx = hash(p1, p2, p3);
311  ItemT* node = SearchList(table[idx], p1, p2, p3);
312  if (node) return node;
313 
314  // not found - create a new one
315  ItemT* newitem = new ItemT(id_gen.Get());
316  newitem->p1 = p1;
317  newitem->p2 = p2;
318  newitem->p3 = p3;
319 
320  // insert into hashtable
321  Insert(idx, newitem);
322 
323  // also, maintain the mapping ID -> item
324  if (id_to_item.Size() <= newitem->id) {
325  id_to_item.SetSize(newitem->id + 1, NULL);
326  }
327  id_to_item[newitem->id] = newitem;
328 
329  Rehash();
330  return newitem;
331 }
332 
333 template<typename ItemT>
334 ItemT* HashTable<ItemT>::SearchList(ItemT* item, int p1, int p2) const
335 {
336  while (item != NULL)
337  {
338  if (item->p1 == p1 && item->p2 == p2) return item;
339  item = item->next;
340  }
341  return NULL;
342 }
343 
344 template<typename ItemT>
345 ItemT* HashTable<ItemT>::SearchList(ItemT* item, int p1, int p2, int p3) const
346 {
347  while (item != NULL)
348  {
349  if (item->p1 == p1 && item->p2 == p2 && item->p3 == p3) return item;
350  item = item->next;
351  }
352  return NULL;
353 }
354 
355 template<typename ItemT>
357 {
358  const int fill_factor = 2;
359  int old_size = mask+1;
360 
361  // is the table overfull?
362  if (num_items > old_size * fill_factor)
363  {
364  delete [] table;
365 
366  // double the table size
367  int new_size = 2*old_size;
368  table = new ItemT*[new_size];
369  memset(table, 0, new_size * sizeof(ItemT*));
370  mask = new_size-1;
371 
372 #ifdef MFEM_DEBUG
373  std::cout << _MFEM_FUNC_NAME << ": rehashing to size " << new_size
374  << std::endl;
375 #endif
376 
377  // reinsert all items
378  num_items = 0;
379  for (Iterator it(*this); it; ++it)
380  Insert(hash(it), it);
381  }
382 }
383 
384 template<typename ItemT>
385 void HashTable<ItemT>::Unlink(ItemT* item)
386 {
387  // remove item from the linked list
388  ItemT** ptr = table + hash(item);
389  while (*ptr)
390  {
391  if (*ptr == item)
392  {
393  *ptr = item->next;
394  num_items--;
395  return;
396  }
397  ptr = &((*ptr)->next);
398  }
399  mfem_error("HashTable<>::Unlink: item not found!");
400 }
401 
402 template<typename ItemT>
403 void HashTable<ItemT>::Delete(ItemT* item)
404 {
405  // remove item from the hash table
406  Unlink(item);
407 
408  // remove from the (ID -> item) map
409  id_to_item[item->id] = NULL;
410 
411  // reuse the ID in the future
412  id_gen.Reuse(item->id);
413 
414  delete item;
415 }
416 
417 template<typename ItemT>
418 void HashTable<ItemT>::Reparent(ItemT* item, int new_p1, int new_p2)
419 {
420  Unlink(item);
421 
422  if (new_p1 > new_p2) std::swap(new_p1, new_p2);
423  item->p1 = new_p1;
424  item->p2 = new_p2;
425 
426  // reinsert under new parent IDs
427  int new_idx = hash(new_p1, new_p2);
428  Insert(new_idx, item);
429 }
430 
431 template<typename ItemT>
432 void HashTable<ItemT>::Reparent(ItemT* item,
433  int new_p1, int new_p2, int new_p3, int new_p4)
434 {
435  Unlink(item);
436 
437  internal::sort4(new_p1, new_p2, new_p3, new_p4);
438  item->p1 = new_p1;
439  item->p2 = new_p2;
440  item->p3 = new_p3;
441 
442  // reinsert under new parent IDs
443  int new_idx = hash(new_p1, new_p2, new_p3);
444  Insert(new_idx, item);
445 }
446 
447 template<typename ItemT>
449 {
450  while (cur_id < hash_table.id_to_item.Size()-1)
451  {
452  ++cur_id;
453  cur_item = hash_table.id_to_item[cur_id];
454  if (cur_item) return;
455  }
456 
457  // no more items
458  cur_item = NULL;
459 }
460 
461 template<typename ItemT>
463 {
464  return sizeof(*this) +
465  ((mask+1) + id_to_item.Capacity()) * sizeof(ItemT*) +
466  num_items * sizeof(ItemT);
467 }
468 
469 } // namespace mfem
470 
471 #endif
int Size() const
Logical size of the array.
Definition: array.hpp:108
HashTable< ItemT > & hash_table
Definition: hash.hpp:167
HashTable(int init_size=32 *1024)
Definition: hash.hpp:214
Iterator(HashTable< ItemT > &table)
Definition: hash.hpp:157
Iterator over items contained in the HashTable.
Definition: hash.hpp:154
long MemoryUsage() const
Return total size of allocated memory (tables plus items), in bytes.
Definition: hash.hpp:462
void Reparent(ItemT *item, int new_p1, int new_p2)
Make an item hashed under different parent IDs.
Definition: hash.hpp:418
ItemT ** table
Definition: hash.hpp:179
int hash(const Hashed2< ItemT > *item) const
Definition: hash.hpp:191
ItemT & operator*() const
Definition: hash.hpp:161
void Rehash()
Check table load and resize if necessary.
Definition: hash.hpp:356
int hash(int p1, int p2) const
Definition: hash.hpp:184
void Delete(ItemT *item)
Remove an item from the hash table and also delete the item itself.
Definition: hash.hpp:403
ItemT * Get(OtherT *i1, OtherT *i2)
Definition: hash.hpp:128
ItemT * Get(int p1, int p2)
Get an item whose parents are p1, p2... Create it if it doesn&#39;t exist.
Definition: hash.hpp:279
ItemT * Peek(int id) const
Obtains an item given its ID.
Definition: hash.hpp:144
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:330
ItemT * SearchList(ItemT *item, int p1, int p2) const
Definition: hash.hpp:334
ItemT * Peek(OtherT *i1, OtherT *i2, OtherT *i3, OtherT *i4) const
Definition: hash.hpp:140
Iterator & operator++()
Definition: hash.hpp:164
Derived * next
Definition: hash.hpp:78
int hash(const Hashed4< ItemT > *item) const
Definition: hash.hpp:194
Array< ItemT * > id_to_item
mapping table for the Peek(id) method
Definition: hash.hpp:207
ItemT * Peek(int p1, int p2) const
Get an item whose parents are p1, p2... Return NULL if it doesn&#39;t exist.
Definition: hash.hpp:256
void swap(Vector *v1, Vector *v2)
Definition: vector.cpp:213
void mfem_error(const char *msg)
Definition: error.cpp:23
void DeleteLast()
Delete the last entry.
Definition: array.hpp:146
void Reuse(int id)
Return an ID previously generated by &#39;Get&#39;.
Definition: hash.hpp:43
Derived * next
Definition: hash.hpp:65
void Insert(int idx, ItemT *item)
Definition: hash.hpp:270
IdGenerator(int first_id=0)
Definition: hash.hpp:28
Hashed4(int id)
Definition: hash.hpp:80
int Capacity() const
Definition: array.hpp:112
void Unlink(ItemT *item)
Definition: hash.hpp:385
T & Last()
Return the last element in the array.
Definition: array.hpp:361
Hashed2(int id)
Definition: hash.hpp:67
ItemT * Peek(OtherT *i1, OtherT *i2) const
Definition: hash.hpp:136
ItemT * operator->() const
Definition: hash.hpp:162
ItemT * Get(OtherT *i1, OtherT *i2, OtherT *i3, OtherT *i4)
Definition: hash.hpp:132
int Get()
Generate a unique ID.
Definition: hash.hpp:31
IdGenerator id_gen
id generator for new items
Definition: hash.hpp:206
int hash(int p1, int p2, int p3) const
Definition: hash.hpp:187