Aleph-w  1.9
General library for algorithms and data structures
tpl_dynSetHash.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 # ifndef TPL_DYNSETHASH_H
28 # define TPL_DYNSETHASH_H
29 
30 # include <algorithm>
31 # include <typeinfo>
32 # include <ahDry.H>
33 # include <ahIterator.H>
34 # include <primes.H>
35 # include <htlist.H>
36 # include <tpl_dynArray.H>
37 # include <tpl_dynMapOhash.H>
38 # include <tpl_dynLhash.H>
39 # include <tpl_linHash.H>
40 
41 
42 namespace Aleph
43 {
44 
58  template <typename Key,
59  template <typename, class> class HashTable = LhashTable,
60  class Cmp = Aleph::equal_to<Key>>
62  : public HashTable<Key, Cmp>,
63  public GenericTraverse<DynHashTable<Key, HashTable, Cmp>>,
64  public LocateFunctions<DynHashTable<Key, HashTable, Cmp>, Key>,
65  public FunctionalMethods<DynHashTable<Key, HashTable, Cmp>, Key>,
66  public GenericKeys<DynHashTable<Key, HashTable, Cmp>, Key>,
67  public EqualToMethod<DynHashTable<Key, HashTable, Cmp>>,
68  public StlAlephIterator<DynHashTable<Key, HashTable, Cmp>>
69 {
70 protected:
71 
72  using Base = HashTable<Key, Cmp>;
73 
74  using Bucket = typename HashTable<Key, Cmp>::Bucket;
75 
76 public:
77 
79  using Hash_Fct = typename Base::Hash_Fct;
80 
81  using Hash_Fct_Ptr = typename Base::Hash_Fct_Ptr;
82 
83  using Key_Type = Key;
84 
85  using Item_Type = Key;
86 
97  DynHashTable(size_t len = Primes::DefaultPrime,
98  Hash_Fct_Ptr hash_fct = Aleph::dft_hash_fct<Key>,
99  Cmp cmp = Cmp(),
100  float lower_alpha = hash_default_lower_alpha,
101  float upper_alpha = hash_default_upper_alpha)
102  : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
103  {
104  // empty
105  }
106 
107  DynHashTable(size_t len, Hash_Fct hash_fct, Cmp cmp,
108  float lower_alpha, float upper_alpha)
109  : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
110  {
111  // empty
112  }
113 
114 private:
115 
116  void copy(const DynHashTable & other)
117  {
118  for (typename Base::Iterator it(other); it.has_curr(); it.next_ne())
119  {
120  Bucket * bucket = (Bucket*) it.get_curr_ne();
121  insert(bucket->get_key());
122  }
123  }
124 
125 public:
126 
127  DynHashTable(const DynHashTable & other)
128  : Base(other.len, other.hash_fct,
129  const_cast<DynHashTable&>(other).get_compare(),
130  other.lower_alpha, other.upper_alpha, true, true)
131  {
132  copy(other);
133  }
134 
135  DynHashTable(DynHashTable && other)
136  : Base(other.len, other.hash_fct, other.get_compare(),
137  other.lower_alpha, other.upper_alpha, true, true)
138  {
139  this->swap(other);
140  }
141 
142  Special_Ctors(DynHashTable, Key);
143 
144  ~DynHashTable()
145  {
146  this->empty();
147  }
148 
149  DynHashTable & operator = (const DynHashTable & other)
150  {
151  if (this == &other)
152  return *this;
153 
154  this->empty();
155  copy(other);
156 
157  return *this;
158  }
159 
160  DynHashTable & operator = (DynHashTable && other) noexcept
161  {
162  this->swap(other);
163  return *this;
164  }
165 
166 protected:
167 
168  Key * insert_bucket(Bucket * bucket)
169  {
170  Bucket * ret_val = (Bucket*) this->Base::insert(bucket);
171  if (ret_val == nullptr) // is the key in the table?
172  { // yes! ==> free bucket
173  delete bucket;
174  return nullptr;
175  }
176 
177  return &ret_val->get_key();
178  }
179 
180  tuple<Key*, bool> search_or_insert_bucket(Bucket * bucket)
181  {
182  Bucket * ret_val = (Bucket*) this->Base::search_or_insert(bucket);
183  if (ret_val != bucket) // is the key in the table?
184  { // yes! ==> free bucket
185  delete bucket;
186  return make_tuple(&ret_val->get_key(), true);
187  }
188 
189  return make_tuple(&ret_val->get_key(), false);
190  }
191 
192 public:
193 
196  Key * insert(const Key & key)
197  {
198  return insert_bucket(new Bucket(key));
199  }
200 
201  Key * insert(Key && key)
202  {
203  return insert_bucket(new Bucket(std::forward<Key>(key)));
204  }
205 
206  Key * search_or_insert(const Key & key)
207  {
208  return get<0>(search_or_insert_bucket(new Bucket(key)));
209  }
210 
211  Key * search_or_insert(Key && key)
212  {
213  return get<0>(search_or_insert_bucket(new Bucket(std::forward<Key>(key))));
214  }
215 
216  // Retorna true si key ya se encuentra en la tabla. De lo contrario,
217  // se inserta key y se retorna false
218  pair<Key*, bool> contains_or_insert(const Key & key)
219  {
220  return search_or_insert_bucket(new Bucket(key));
221  }
222 
223  pair<Key*, bool> contains_or_insert(Key && key)
224  {
225  return search_or_insert_bucket(new Bucket(std::forward<Key>(key)));
226  }
227 
228  Key * add(const Key & key)
229  {
230  return insert_bucket(new Bucket(key));
231  }
232 
233  Key * add(Key && key)
234  {
235  return insert_bucket(new Bucket(std::forward<Key>(key)));
236  }
237 
238  Key * append(const Key & key)
239  {
240  return insert_bucket(new Bucket(key));
241  }
242 
243  Key * append(Key && key)
244  {
245  return insert_bucket(new Bucket(std::forward<Key>(key)));
246  }
247 
251  Key * search(const Key & key) const
252  {
253  Bucket * bucket = (Bucket*) this->Base::search(key);
254  return bucket != nullptr ? &bucket->get_key() : nullptr;
255  }
256 
257  bool has(const Key & key) const
258  {
259  return this->Base::search(key) != nullptr;
260  }
261 
262  bool contains(const Key & key) const { return has(key); }
263 
264  const Key & find(const Key & key) const
265  {
266  Bucket * bucket = (Bucket*) this->Base::search(key);
267  if (bucket == nullptr)
268  throw std::domain_error("Key not found in hash");
269 
270  return bucket->get_key();
271  }
272 
273  Key & find(const Key & key)
274  {
275  Bucket * bucket = (Bucket*) this->Base::search(key);
276 
277  if (bucket == nullptr)
278  throw std::domain_error("Key not found in hash");
279 
280  return bucket->get_key();
281  }
282 
283 protected:
284 
285  static Bucket * key_to_bucket(Key * key)
286  {
287  Bucket * ret_val = 0;
288  size_t offset = reinterpret_cast<size_t>(&ret_val->get_key());
289 
290  return reinterpret_cast<Bucket*>(reinterpret_cast<size_t>(key) - offset);
291  }
292 
293 public:
294 
297  void remove(Key * key)
298  {
299  Bucket * bucket = key_to_bucket(key);
300  this->Base::remove(bucket);
301  delete bucket;
302  }
303 
304  Key remove(const Key & key)
305  {
306  Bucket * bucket = (Bucket*) this->Base::search(key);
307  if (bucket == nullptr)
308  throw std::domain_error("Key not found in hash table");
309 
310  this->Base::remove(bucket);
311  auto ret_val = bucket->get_key();
312  delete bucket;
313  return ret_val;
314  }
315 
316  class Iterator : public Base::Iterator
317  {
318  public:
319 
320  using Item_Type = Key;
321 
322  using Set_Type = DynHashTable;
323 
324  Iterator(const DynHashTable & table) : Base::Iterator(table) {}
325 
326  Key & get_curr_ne() noexcept
327  {
328  return this->Base::Iterator::get_curr_ne()->get_key();
329  }
330 
331  const Key & get_curr_ne() const noexcept
332  {
333  return const_cast<Iterator*>(this)->get_curr_ne();
334  }
335 
336  const Key & get_curr() const
337  {
338  return const_cast<Iterator*>(this)->get_curr();
339  }
340 
341  Key & get_curr()
342  {
343  return this->Base::Iterator::get_curr()->get_key();
344  }
345 
346  void del() { delete this->Base::Iterator::del(); }
347  };
348 
349  Key & get_first() const
350  {
351  return this->get_it().get_curr();
352  }
353 
354  Key & get_last() const
355  {
356  auto it = this->get_it();
357  it.reset_last();
358  return it.get_curr();
359  }
360 };
361 
366  template <typename Key, class Cmp = Aleph::equal_to<Key>>
367 struct DynSetLhash : public DynHashTable<Key, LhashTable, Cmp>
368 {
370  using Base::Base;
371 };
372 
377  template <typename Key, class Cmp = Aleph::equal_to<Key>>
378 struct DynSetLinHash : public DynHashTable<Key, LinearHashTable, Cmp>
379 {
381  using Base::Base;
382 };
383 
388 template <typename Key, class Cmp = Aleph::equal_to<Key>>
390 
395 template <typename Key, typename Data,
396  template <class, class> class HashTable = LhashTable,
397  class Cmp = Aleph::equal_to<Key>>
398 class DynMapHashTable
399  : public DynHashTable<std::pair<Key, Data>,
400  HashTable, Dft_Pair_Cmp<Key, Data, Cmp>>
401 {
402  using Pair = std::pair<Key, Data>;
403 
404  using Base =
405  DynHashTable<std::pair<Key, Data>, HashTable, Dft_Pair_Cmp<Key, Data, Cmp>>;
406 
407  using Bucket = typename Base::Bucket;
408 
409 public:
410 
411  static Data & get_data(const Key & key)
412  {
413  return key_to_pair<Key, Data>(&const_cast<Key&>(key))->second;
414  }
415 
416  static const Key & get_key(Data * data_ptr)
417  {
418  return data_to_pair<Key, Data>(data_ptr)->first;
419  }
420 
421  using Value_Type = Data;
422 
423  // using Base::Base; // no more need. But I don't remember why I put it
424  using Base::insert; // in this way, insert with a pair is exported
425  using Iterator = typename Base::Iterator;
426 
427  using Hash_Fct = std::function<size_t(const Key&)>;
428  using Hash_Fct_Ptr = size_t (*) (const Key &);
429 
430  DynMapHashTable(size_t len = Primes::DefaultPrime,
431  Hash_Fct_Ptr hash_fct = dft_hash_fct,
432  Cmp cmp = Cmp(),
433  float lower_alpha = hash_default_lower_alpha,
434  float upper_alpha = hash_default_upper_alpha)
435  : Base(len, std::bind(map_hash_fct<Key, Data, Hash_Fct>,
436  hash_fct, std::placeholders::_1),
437  Dft_Pair_Cmp<Key, Data, Cmp>(cmp), lower_alpha, upper_alpha) {}
438 
442  Pair * insert(const Key & key, const Data & data)
443  {
444  return this->insert_bucket(new typename Base::Bucket (Pair(key, data)));
445  }
446 
447  Pair * insert(const Key & key, Data && data)
448  {
449  return this->insert_bucket
450  (new typename Base::Bucket(Pair(key, forward<Data>(data))));
451  }
452 
453  Pair * insert(Key && key, Data && data)
454  {
455  return this->insert_bucket
456  (new typename Base::Bucket(Pair(forward<Key>(key), forward<Data>(data))));
457  }
458 
459  Pair * insert(Key && key, const Data & data)
460  {
461  return this->insert_bucket
462  (new typename Base::Bucket(Pair(forward<Key>(key), data)));
463  }
464 
468  Pair * search(const Key & key) const
469  {
470  return this->Base::search(Pair(key, Data()));
471  }
472 
473  Pair * search(Key && key) const
474  {
475  return this->Base::search(Pair(forward<Key>(key), Data()));
476  }
477 
478  bool has(const Key & key) const { return search(key) != nullptr; }
479 
480  bool has(Key && key) const { return search(forward<Key>(key)) != nullptr; }
481 
482  bool contains(const Key & key) const { return has(key); }
483 
484  bool contains(Key && key) const { return has(forward<Key>(key)); }
485 
486  Data & find(const Key & key)
487  {
488  return Base::find(Pair(key, Data())).second;
489  }
490 
491  const Data & find(const Key & key) const
492  {
493  return Base::find(Pair(key, Data())).second;
494  }
495 
496  Data & operator [] (const Key & key)
497  {
498  return this->search_or_insert(Pair(key, Data()))->second;
499  }
500 
501  const Data & operator [] (const Key & key) const
502  {
503  return this->find(key);
504  }
505 
506  Data & operator [] (Key && key)
507  {
508  return this->search_or_insert(Pair(forward<Key>(key), Data()))->second;
509  }
510 
511  const Data & operator [] (Key && key) const
512  {
513  return this->find(forward<Key>(key));
514  }
515 
518  void remove_by_data(Data & data)
519  {
520  Base::remove(data_to_pair<Key, Data>(&data));
521  }
522 
523  Data remove(const Key & key)
524  {
525  auto p = Base::remove(Pair(key, Data()));
526  return p.second;
527  }
528 
529  Data remove(Key && key)
530  {
531  auto p = Base::remove(Pair(forward<Key>(key), Data()));
532  return p.second;
533  }
534 
535  DynList<Key> keys() const
536  {
537  return this->template maps<Key>([] (auto p) { return p.first; });
538  }
539 
540  DynList<Key> values() const
541  {
542  return this->template maps<Data>([] (auto p) { return p.second; });
543  }
544 
545  DynList<Data*> values_ptr()
546  {
547  DynList<Data*> ret;
548  for (Iterator it(*this); it.has_curr(); it.next_ne())
549  ret.append(&it.get_curr_ne().second);
550  return ret;
551  }
552 
553  DynList<Pair*> items_ptr()
554  {
555  DynList<Pair*> ret;
556  for (Iterator it(*this); it.has_curr(); it.next_ne())
557  ret.append(&it.get_curr_ne());
558  return ret;
559  }
560 };
561 
566 template <typename Key, typename Data,
567  class Cmp = Aleph::equal_to<Key>>
568 using DynMapLinHash = DynMapHashTable<Key, Data, LinearHashTable, Cmp>;
569 
574 template <typename Key, typename Data,
575  class Cmp = Aleph::equal_to<Key>>
576 using DynMapHash = DynMapHashTable<Key, Data, LhashTable, Cmp>;
577 
578 
579 // Implementation de coming from ahFunctional.H
580 
581 template <typename T, template <typename> class Container> inline
582 DynList<T> join(const Container<T> & c1, const Container<T> & c2)
583 {
584  DynSetLhash<T> table(c1);
585  c2.for_each([&table] (const T & item)
586  {
587  table.insert(item);
588  });
589  return table.keys();
590 }
591 
592 template <typename T, template <typename> class Container = DynList> inline
593 DynList<T> intercept(const Container<T> & c1, const Container<T> & c2)
594 {
595  DynSetLhash<T> set1 = c1;
596  DynSetLhash<T> set2 = c2;
597  return set1.filter([&set2] (const T & i) { return set2.contains(i); });
598 }
599 
600 template <typename T, template <typename> class Container> inline
601 DynList<T> unique(const Container<T> & c)
602 {
603  return DynSetLhash<T>(c).keys();
604 }
605 
606 template <typename T, template <typename> class Container> inline
607 DynList<T> repeated(const Container<T> & c)
608 {
609  DynList<T> ret;
610  DynSetLhash<T> table;
611 
612  c.for_each([&table, &ret] (const T & i)
613  {
614  auto * ptr = table.insert(i);
615  if (ptr == nullptr)
616  ret.append(i);
617  });
618 
619  return ret;
620 }
621 
622 template <typename T, template <typename> class Container> inline
623 DynList<std::pair<T, size_t>> repeated_with_index(const Container<T> & c)
624 {
626  DynSetLhash<T> table;
627 
628  size_t i = 0;
629  c.for_each([&table, &ret, &i] (const T & item)
630  {
631  auto * ptr = table.insert(item);
632  if (ptr == nullptr)
633  ret.append(std::pair<T, size_t>(item, i));
634  ++i;
635  });
636 
637  return ret;
638 }
639 
640 } // end namespace Aleph
641 
642 # endif // TPL_DYNSETHASH_H
643 
644 
645 
646 
Definition: htlist.H:450
Definition: htlist.H:1290
Definition: htlist.H:133
DynList< T > keys() const
Definition: htlist.H:1306
void for_each(Operation &operation) noexcept(noexcept(operation))
Definition: htlist.H:589
Key * search(const Key &key) const
Definition: tpl_dynSetHash.H:251
Definition: htlist.H:45
Definition: ah-comb.H:35
DynHashTable(size_t len=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=Aleph::dft_hash_fct< Key >, Cmp cmp=Cmp(), float lower_alpha=hash_default_lower_alpha, float upper_alpha=hash_default_upper_alpha)
Definition: tpl_dynSetHash.H:97
Node * join(Node *t1, Node *t2, Node *&dup, Compare cmp=Compare()) noexcept
Definition: tpl_binNodeUtils.H:1855
typename Base::Hash_Fct Hash_Fct
El tipo de función hash.
Definition: tpl_dynSetHash.H:79
Key * insert(const Key &key)
Definition: tpl_dynSetHash.H:196
Definition: tpl_dynSetHash.H:61
Definition: ahDry.H:41
Definition: tpl_lhash.H:660
T & append(const T &item)
Definition: htlist.H:1471
Definition: htlist.H:1323

Leandro Rabindranath León