Aleph-w  1.5a.2
Biblioteca general de algoritmos y estructuras de datos
 Todo Clases Archivos Funciones Variables 'typedefs' Enumeraciones Amigas Grupos Páginas
tpl_lhash.H
1 
2 # ifndef TPL_LHASH_H
3 # define TPL_LHASH_H
4 
5 # include <iostream>
6 # include <primes.H>
7 # include <hash-fct.H>
8 # include <tpl_dlist.H>
9 # include <tpl_dynArray.H>
10 # include <hash-dry.H>
11 
12 # ifdef N
13 # define NBACKUP N
14 # undef N
15 # endif
16 
17 # ifdef M
18 # define MBACKUP M
19 # undef M
20 # endif
21 
22 using namespace Primes;
23 
24 using namespace Aleph;
25 
26 namespace Aleph {
27 
47  template <typename Key, class BucketType, class Cmp>
49 {
50 public:
51 
52  typedef BucketType Bucket;
53 
54  typedef size_t (*Hash_Fct)(const Key &);
55 
56  typedef Key Key_Type;
57 
58  typedef Key Item_Type;
59 
60 protected:
61 
62  Hash_Fct hash_fct;
63 
64 private:
65 
66  typedef Dnode<Key> BucketList;// Tipo lista cubetas
67  typedef typename Dnode<Key>::Iterator BucketItor;// Iterador cubetas
68  typedef Dnode<Key> Node; // Sinónimo nodo
69 
70  BucketList * table;
71 
72 protected:
73 
74  size_t len; // Tamaño de la tabla
75  float lower_alpha;
76  float upper_alpha;
77 
78 private:
79 
80  size_t N; // Número de elementos de la tabla
81  size_t busy_slots_counter; // Cantidad de entradas ocupadas
82  bool remove_all_buckets; // liberar cubetas en destructor
83  bool with_resize;
84 
85 public:
86 
95  GenLhashTable(Hash_Fct __hash_fct,
96  size_t table_size = Primes::DefaultPrime,
97  const float & __lower_alpha = hash_default_lower_alpha,
98  const float & __upper_alpha = hash_default_upper_alpha,
99  const bool __remove_all_buckets = true,
100  const bool __with_resize = true)
101  throw(std::exception, std::bad_alloc)
102  : hash_fct(__hash_fct), table(NULL),
103  len(Primes::next_prime(table_size)),
104  lower_alpha(__lower_alpha), upper_alpha(__upper_alpha),
105  N(0), busy_slots_counter(0), remove_all_buckets(__remove_all_buckets),
106  with_resize(__with_resize)
107  {
108  table = new BucketList [len];
109  }
110 
111  void swap(GenLhashTable & other)
112  {
113  std::swap(hash_fct, other.hash_fct);
114  std::swap(table, other.table);
115  std::swap(len, other.len);
116  std::swap(N, other.N);
117  std::swap(busy_slots_counter, other.busy_slots_counter);
118  std::swap(remove_all_buckets, other.remove_all_buckets);
119  std::swap(with_resize, other.with_resize);
120  }
121 
123  void empty()
124  {
125  for (int i = 0; i < len; ++i)
126  for (BucketItor itor(table[i]); itor.has_curr(); /* nada */)
127  delete (Bucket*) itor.del();
128  busy_slots_counter = N = 0;
129  }
130 
131 private:
132 
133  Bucket * search_in_bucket_list(BucketList & list, const Key & key) const
134  {
135  for (BucketItor it(list); it.has_curr(); it.next())
136  {
137  Bucket * bucket = static_cast<Bucket*>(it.get_current());
138  if (Cmp () (key, bucket->get_key()))
139  return bucket;
140  }
141 
142  return NULL;
143  }
144 
145 public:
146 
147  Hash_Fct get_hash_fct() const { return hash_fct; }
148 
150  void set_hash_fct(Hash_Fct fct)
151  {
152  hash_fct = fct;
153  }
154 
156  float current_alpha() const { return 1.0*N/len; }
157 
160  Bucket * insert(Bucket * bucket)
161  {
162  const size_t i = (*hash_fct)(bucket->get_key()) % len;
163  BucketList & list = table[i];
164 
165  if (list.is_empty()) // ¿está vacía la lista table[i]?
166  ++busy_slots_counter; // sí ==> actualizar contador ocupación
167 
168  if (search_in_bucket_list(list, bucket->get_key()) != NULL)
169  return NULL;
170 
171  list.append(bucket); // insertar cubeta al final
172  ++N;
173 
174  if (with_resize and current_alpha() >= upper_alpha)
175  resize(next_prime(2*len));
176 
177  return bucket;
178  }
179 
182  Bucket * search(const Key & key) const
183  {
184  const size_t i = (*hash_fct)(key) % len;
185  return search_in_bucket_list(table[i], key);
186  }
187 
188 private:
189 
190  // Remove without perform resizing. This is strictly required inside
191  // the del() method of Iterator. In addtion dries the code
192  Bucket * remove_bucket(Bucket * bucket)
193  { // guarda próxima colisión
194  Bucket * next = static_cast<Bucket*>(bucket->get_next());
195  bucket->del(); // eliminar de su lista de colisiones
196  if (next->is_empty()) // ¿la lista devino vacía?
197  --busy_slots_counter;// sí ==> actualizar contador listas ocupadas
198 
199  --N;
200 
201  return bucket;
202  }
203 
204 public:
205 
209  Bucket * remove(Bucket * bucket)
210  { // guarda próxima colisión
211  remove_bucket(bucket);
212 
213  if (with_resize and current_alpha() < lower_alpha)
214  resize(next_prime(len/2));
215 
216  return bucket;
217  }
218 
222  size_t resize(size_t new_size) throw(std::exception, std::bad_alloc)
223  {
224  I(len > 0);
225 
226  if (new_size == len or new_size == 0)
227  return len;
228 
229  BucketList * new_table = new BucketList [new_size];
230  BucketList * old_table = table; // guardar estado tabla actual
231  const size_t old_size = len;
232  table = new_table; // tabla vacía con nuevo arreglo
233  len = new_size;
234  busy_slots_counter = N = 0;
235 
236  for (int i = 0; i < old_size; ++i) // reinsertar cubetas
237  // recorrer lista colisiones en old_table[i]
238  for (BucketItor it(old_table[i]); it.has_curr(); /* Nada */)
239  insert((Bucket*) it.del()); // eliminar e insertar en table[]
240 
241  delete [] old_table; // liberar memoria antigua tabla
242 
243  return len;
244  }
245 
249  virtual ~GenLhashTable()
250  {
251  if (remove_all_buckets)
252  empty();
253 
254  delete [] table;
255  }
256 
259  Bucket * search_next(Bucket * bucket) const
260  {
261  I(bucket != NULL);
262 
263  const size_t i = (*hash_fct)(bucket->get_key()) % len;
264 
265  BucketItor itor(table[i]);
266  itor.set(bucket);
267 
268  while (true)
269  {
270  itor.next();
271 
272  if (not itor.has_curr())
273  return NULL;
274 
275  Bucket * node = static_cast<Bucket*>(itor.get_curr());
276 
277  if (Cmp () (bucket->get_key(), node->get_key()))
278  return node;
279  }
280  }
281 
283  const size_t & capacity() const { return len; }
284 
286  const size_t & size() const { return N; }
287 
289  const size_t & get_num_busy_slots() const { return busy_slots_counter; }
290 
291  bool is_empty() const { return N == 0; }
292 
299  class Iterator
300  {
301  private:
302 
303  int curr_index; // índice en table
304  BucketItor curr_itor; // Iterador sobre table[curr_index]
305  GenLhashTable * hash_table;
306 
307  // Avanza a próxima entrada de table
308  void locate_next_available_entry()
309  {
310  while (true)
311  {
312  if (curr_index == hash_table->len)
313  throw std::overflow_error ("hash table iterator overflow");
314 
315  if (curr_index == hash_table->len - 1)
316  { // quedar en estado overflow
317  curr_index = hash_table->len;
318  return;
319  }
320 
321  ++curr_index;
322 
323  if (not hash_table->table[curr_index].is_empty())
324  {
325  BucketItor itor(hash_table->table[curr_index]);
326  curr_itor = itor;
327  return;
328  }
329  }
330  }
331 
332  void locate_next_available_bucket()
333  {
334  curr_itor.next();
335 
336  if (not curr_itor.has_curr())
337  locate_next_available_entry();
338  }
339 
340  void locate_prev_available_entry()
341  {
342  while (true)
343  {
344  if (curr_index == -1)
345  throw std::underflow_error ("hash table iterator underflow");
346 
347  if (curr_index == 0)
348  { // quedar en estado underflow
349  curr_index = -1;
350  return;
351  }
352 
353  --curr_index;
354 
355  if (not hash_table->table[curr_index].is_empty())
356  {
357  BucketItor itor(hash_table->table[curr_index]);
358  curr_itor = itor;
359  curr_itor.reset_last();
360  return;
361  }
362  }
363  }
364 
365  void locate_prev_available_bucket()
366  {
367  curr_itor.prev();
368 
369  if (not curr_itor.has_curr())
370  locate_prev_available_entry();
371  }
372 
373 public:
374 
377 
379  typedef Bucket * Item_Type;
380 
382  Iterator(const GenLhashTable & table)
383  : curr_index(-1), hash_table(&const_cast<GenLhashTable&>(table))
384  {
385  try
386  {
387  locate_next_available_entry();
388  }
389  catch (std::overflow_error)
390  { /* nothing to do */ }
391  }
392 
394  Iterator() : curr_index(-1), hash_table(NULL)
395  {
396  // Empty
397  }
398 
400  void reset_first()
401  {
402  curr_index = -1;
403 
404  locate_next_available_entry();
405  }
406 
408  void reset_last()
409  {
410  curr_index = hash_table->len;
411 
412  locate_prev_available_entry();
413  }
414 
416  bool has_curr() const
417  {
418  return curr_index >= 0 and curr_index < hash_table->len;
419  }
420 
422  Bucket * get_curr()
423  throw(std::exception, std::overflow_error, std::underflow_error)
424  {
425  if (curr_index == -1)
426  throw std::underflow_error ("hash table iterator underflow");
427 
428  if (curr_index == hash_table->len)
429  throw std::overflow_error ("hash table iterator overflow");
430 
431  return static_cast<Bucket*>(curr_itor.get_curr());
432  }
433 
435  void next()
436  {
437  if (curr_index == hash_table->len)
438  throw std::overflow_error ("hash table iterator overflow");
439 
440  locate_next_available_bucket();
441  }
442 
444  void prev()
445  {
446  if (curr_index == -1)
447  throw std::underflow_error ("hash table iterator underflow");
448 
449  locate_prev_available_bucket();
450  }
451 
452  Bucket * del()
453  {
454  Bucket * ret_val = get_curr();
455  next();
456  hash_table->remove_bucket(ret_val);
457  return ret_val;
458  }
459  };
460 
461  HASH_STATS();
462 };
463 
471  template <typename Key>
472 class LhashBucket : public Dnode<Key>
473 {
474 public:
475 
477  LhashBucket(const LhashBucket & bucket) : Dnode<Key>(bucket) {}
478 
481 
483  LhashBucket(const Key & key) : Dnode<Key>(key) {}
484 
486  Key & get_key() { return this->get_data(); }
487 };
488 
496  template <typename Key>
497 class LhashBucketVtl : public Dnode<Key>
498 {
499 public:
501  LhashBucketVtl(const LhashBucketVtl & bucket) : Dnode<Key>(bucket) {}
502 
505 
507  virtual ~LhashBucketVtl() {}
508 
510  LhashBucketVtl(const Key & key) : Dnode<Key>(key) {}
511 
513  Key & get_key() { return this->get_data(); }
514 };
515 
530  template <typename Key, class Cmp = Aleph::equal_to<Key> >
531 class LhashTable : public GenLhashTable<Key, LhashBucket<Key>, Cmp>
532 {
533 public:
534 
536 
537  using Base::Base;
538 };
539 
554  template <typename Key, class Cmp = Aleph::equal_to<Key> >
555 class LhashTableVtl : public GenLhashTable<Key, LhashBucketVtl<Key>, Cmp>
556 {
557  public:
558 
560 
561  using Base::Base;
562 };
563 
564 
565 } // end namespace Aleph
566 
567 # ifdef NBACKUP
568 # define N NBACKUP
569 # undef NBACKUP
570 # endif
571 
572 # ifdef MBACKUP
573 # define M MBACKUP
574 # undef MBACKUP
575 # endif
576 
577 # endif/* TPL_LHASH_H */
578 
const size_t & size() const
Retorna el número de elementos que contiene la tabla.
Definition: tpl_lhash.H:286
Bucket * insert(Bucket *bucket)
Definition: tpl_lhash.H:160
const size_t & capacity() const
Retorna el tamaño de la tabla.
Definition: tpl_lhash.H:283
virtual ~GenLhashTable()
Definition: tpl_lhash.H:249
LhashBucketVtl()
Instancia una cubeta vacía; valor de clave indefinido.
Definition: tpl_lhash.H:504
void empty()
Vacía la tabla hash; libera memoria de todas las cubetas.
Definition: tpl_lhash.H:123
LhashBucket()
Instancia una cubeta vacía; valor de clave indefinido.
Definition: tpl_lhash.H:480
LhashBucket(const Key &key)
Instancia una cubeta con clave key.
Definition: tpl_lhash.H:483
Bucket * search(const Key &key) const
Definition: tpl_lhash.H:182
Definition: tpl_lhash.H:497
Bucket * Item_Type
El tipo de elemento que retorna get_curr().
Definition: tpl_lhash.H:379
Definition: tpl_lhash.H:48
LhashBucket(const LhashBucket &bucket)
Instancia una cubeta copia de otra.
Definition: tpl_lhash.H:477
Definition: tpl_lhash.H:531
Definition: tpl_lhash.H:555
GenLhashTable(Hash_Fct __hash_fct, size_t table_size=Primes::DefaultPrime, const float &__lower_alpha=hash_default_lower_alpha, const float &__upper_alpha=hash_default_upper_alpha, const bool __remove_all_buckets=true, const bool __with_resize=true)
Definition: tpl_lhash.H:95
Iterator()
Instancia un iterador vacío.
Definition: tpl_lhash.H:394
void prev()
Retrocede el iterador una cubeta.
Definition: tpl_lhash.H:444
void reset_first()
Reinicia el iterador sobre la primera cubeta.
Definition: tpl_lhash.H:400
Bucket * search_next(Bucket *bucket) const
Definition: tpl_lhash.H:259
void reset_last()
Reinicia el iterador sobre la última cubeta.
Definition: tpl_lhash.H:408
GenLhashTable Set_Type
El tipo de conjunto sobre el cual se itera.
Definition: tpl_lhash.H:376
Definition: tpl_lhash.H:472
size_t resize(size_t new_size)
Definition: tpl_lhash.H:222
LhashBucketVtl(const Key &key)
Instancia una cubeta con clave key.
Definition: tpl_lhash.H:510
virtual ~LhashBucketVtl()
destructor virtual.
Definition: tpl_lhash.H:507
LhashBucketVtl(const LhashBucketVtl &bucket)
Instancia una cubeta copia de otra.
Definition: tpl_lhash.H:501
const size_t & get_num_busy_slots() const
Retorna la cantidad de entradas del arreglo que están ocupadas.
Definition: tpl_lhash.H:289
Key & get_key()
Retorna la clave de indización de la cubeta.
Definition: tpl_lhash.H:486
Iterator(const GenLhashTable &table)
Instancia un iterador sobre la tabla hash table.
Definition: tpl_lhash.H:382
void set_hash_fct(Hash_Fct fct)
Set the internal hash function.
Definition: tpl_lhash.H:150
Bucket * get_curr()
Retorna la cubeta actual.
Definition: tpl_lhash.H:422
float current_alpha() const
return the current table load
Definition: tpl_lhash.H:156
Definition: List.H:23
void next()
Avanza el iterador una cubeta.
Definition: tpl_lhash.H:435
Key & get_key()
Retorna la clave de indización de la cubeta.
Definition: tpl_lhash.H:513
bool has_curr() const
Retorna true si el iterador tiene cubeta actual.
Definition: tpl_lhash.H:416
Definition: tpl_lhash.H:299

Leandro Rabindranath León