DeSiGNAR  0.5a
Data Structures General Library
hash.H
Go to the documentation of this file.
1 /*
2  This file is part of Designar.
3  Copyright (C) 2017 by Alejandro J. Mujica
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Any user request of this software, write to
19 
20  Alejandro Mujica
21 
22  aledrums@gmail.com
23 */
24 
25 # ifndef DSGHASH_H
26 # define DSGHASH_H
27 
28 # include <array.H>
29 # include <list.H>
30 # include <containeralgorithms.H>
31 # include <setalgorithms.H>
32 # include <iterator.H>
33 
34 #undef get16bits
35 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
36  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
37 #define get16bits(d) (*((const uint16_t *) (d)))
38 #endif
39 
40 #if !defined (get16bits)
41 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
42  +(uint32_t)(((const uint8_t *)(d))[0]) )
43 #endif
44 
45 namespace Designar
46 {
47  nat_t super_fast_hash(void *, nat_t);
48 
49  inline nat_t super_fast_hash(const char * key)
50  {
51  return super_fast_hash((void *) key, strlen(key));
52  }
53 
54  inline nat_t super_fast_hash(const std::string & key)
55  {
56  return super_fast_hash((void *) key.c_str(), key.size());
57  }
58 
59  template <typename Key>
60  inline nat_t super_fast_hash(const Key & key)
61  {
62  return super_fast_hash((void *) &key, sizeof(key));
63  }
64 
65  template <typename First, typename Second>
66  inline nat_t super_fast_hash(const std::pair<First, Second> & p)
67  {
68  return super_fast_hash<First>(p.first) ^ super_fast_hash<Second>(p.second);
69  }
70 
71  template <typename Key,
72  class Cmp = std::equal_to<Key>>
73  class LHashTable: private FixedArray<DLList<Key>>,
74  public ContainerAlgorithms<LHashTable<Key, Cmp>, Key>,
75  public SetAlgorithms<LHashTable<Key, Cmp>, Key>
76  {
77  using List = DLList<Key>;
79 
80  public:
81  using ItemType = Key;
82  using KeyType = Key;
83  using DataType = Key;
84  using ValueType = Key;
85  using SizeType = nat_t;
86  using CmpType = Cmp;
87  using HashFctPtr = nat_t (*) (const Key &);
88  using HashFctType = std::function<nat_t(const Key &)>;
89 
90  static constexpr nat_t DFT_SIZE = 32;
91  static constexpr real_t DFT_LOWER_ALPHA = 0.25;
92  static constexpr real_t DFT_UPPER_ALPHA = 0.75;
93 
94  private:
95  nat_t num_items;
96  Cmp & cmp;
97  HashFctType hash_fct;
98  real_t lower_alpha;
99  real_t upper_alpha;
100 
101  void clear_lists();
102 
103  void resize(nat_t);
104 
105 
106  Key * search_in_list(List & list, const Key & k)
107  {
108  return list.search_ptr([&k, this](const auto & item)
109  {
110  return cmp(k, item);
111  });
112  }
113 
114  const Key * search_in_list(const List & list, const Key & k) const
115  {
116  return list.search_ptr([&k, this](const auto & item)
117  {
118  return cmp(k, item);
119  });
120  }
121 
122  nat_t h(const Key & item) const
123  {
124  return hash_fct(item) % BaseArray::get_capacity();
125  }
126 
127  public:
128  LHashTable(nat_t size, Cmp & _cmp, HashFctType fct,
129  real_t _lower_alpha, real_t _upper_alpha)
130  : BaseArray(size), num_items(0), cmp(_cmp), hash_fct(fct),
131  lower_alpha(_lower_alpha), upper_alpha(_upper_alpha)
132  {
133  // empty
134  }
135 
136  LHashTable(nat_t size, Cmp & _cmp, HashFctType fct)
137  : LHashTable(size, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
138  {
139  // empty
140  }
141 
142  LHashTable(nat_t size, Cmp && _cmp, HashFctType fct)
143  : LHashTable(size, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
144  {
145  // empty
146  }
147 
148  LHashTable(nat_t size, Cmp & _cmp, HashFctPtr fct = &super_fast_hash)
149  : LHashTable(size, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
150  {
151  // empty
152  }
153 
154  LHashTable(nat_t size, Cmp && _cmp = Cmp(),
155  HashFctPtr fct = &super_fast_hash)
156  : LHashTable(size, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
157  {
158  // empty
159  }
160 
161  LHashTable(Cmp & _cmp, HashFctType fct)
162  : LHashTable(DFT_SIZE, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
163  {
164  // empty
165  }
166 
167  LHashTable(Cmp && _cmp, HashFctType fct)
168  : LHashTable(DFT_SIZE, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
169  {
170  // empty
171  }
172 
173  LHashTable(Cmp & _cmp, HashFctPtr fct = &super_fast_hash)
174  : LHashTable(DFT_SIZE, _cmp, fct, DFT_LOWER_ALPHA, DFT_UPPER_ALPHA)
175  {
176  // empty
177  }
178 
179  LHashTable(Cmp && _cmp = Cmp(), HashFctPtr fct = &super_fast_hash)
180  : LHashTable(_cmp, fct)
181  {
182  // empty
183  }
184 
186  : BaseArray(h), num_items(h.num_items), cmp(h.cmp), hash_fct(h.hash_fct),
187  lower_alpha(h.lower_alpha), upper_alpha(h.upper_alpha)
188  {
189  // empty
190  }
191 
193  : LHashTable()
194  {
195  swap(h);
196  }
197 
198  LHashTable(const std::initializer_list<Key> &);
199 
201  {
202  if (this == &h)
203  return *this;
204 
205  (BaseArray &) *this = h;
206  num_items = h.num_items;
207  cmp = h.cmp;
208  hash_fct = h.hash_fct;
209  lower_alpha = h.lower_alpha;
210  upper_alpha = h.upper_alpha;
211 
212  return *this;
213  }
214 
216  {
217  swap(h);
218  return *this;
219  }
220 
221  void swap(LHashTable & h)
222  {
223  BaseArray::swap(h);
224  std::swap(num_items, h.num_items);
225  std::swap(cmp, h.cmp);
226  std::swap(hash_fct, h.hash_fct);
227  std::swap(lower_alpha, h.lower_alpha);
228  std::swap(upper_alpha, h.upper_alpha);
229  }
230 
231  Cmp & get_cmp()
232  {
233  return cmp;
234  }
235 
236  const Cmp & get_cmp() const
237  {
238  return cmp;
239  }
240 
241  const HashFctType & get_hash_fct() const
242  {
243  return hash_fct;
244  }
245 
247  {
248  return lower_alpha;
249  }
250 
252  {
253  return upper_alpha;
254  }
255 
257  {
258  lower_alpha = value;
259  }
260 
262  {
263  upper_alpha = value;
264  }
265 
267  {
268  lower_alpha = DFT_LOWER_ALPHA;
269  upper_alpha = DFT_UPPER_ALPHA;
270  }
271 
272  real_t alpha() const
273  {
274  return real_t(num_items) / real_t(BaseArray::get_capacity());
275  }
276 
277  bool is_empty() const
278  {
279  return num_items == 0;
280  }
281 
282  nat_t size() const
283  {
284  return num_items;
285  }
286 
287  nat_t N() const
288  {
289  return size();
290  }
291 
292  nat_t M() const
293  {
294  return BaseArray::get_capacity();
295  }
296 
297  void clear()
298  {
299  clear_lists();
300  num_items = 0;
301  BaseArray::clear();
302  }
303 
304  Key * insert(const Key & item)
305  {
306  nat_t i = h(item);
307 
308  List & list = BaseArray::at(i);
309 
310  if (not list.is_empty() and search_in_list(list, item) != nullptr)
311  return nullptr;
312 
313  if (alpha() < upper_alpha)
314  {
315  ++num_items;
316  return &list.append(item);
317  }
318 
319  resize(BaseArray::get_capacity() * 2);
320  i = h(item);
321  ++num_items;
322  return &BaseArray::at(i).insert(item);
323  }
324 
325  Key * insert(Key && item)
326  {
327  nat_t i = h(item);
328 
329  List & list = BaseArray::at(i);
330 
331  if (not list.is_empty() and search_in_list(list, item) != nullptr)
332  return nullptr;
333 
334  if (alpha() < upper_alpha)
335  {
336  ++num_items;
337  return &list.insert(std::forward<Key>(item));
338  }
339 
340  resize(BaseArray::get_capacity() * 2);
341  i = h(item);
342  ++num_items;
343  return &BaseArray::at(i).insert(std::forward<Key>(item));
344  }
345 
346  Key * insert_dup(const Key & item)
347  {
348  nat_t i = h(item);
349 
350  List & list = BaseArray::at(i);
351 
352  if (alpha() < upper_alpha)
353  {
354  ++num_items;
355  return &list.append(item);
356  }
357 
358  resize(BaseArray::get_capacity() * 2);
359  i = h(item);
360  ++num_items;
361  return &BaseArray::at(i).insert(item);
362  }
363 
364  Key * insert_dup(Key && item)
365  {
366  nat_t i = h(item);
367 
368  List & list = BaseArray::at(i);
369 
370  if (alpha() < upper_alpha)
371  {
372  ++num_items;
373  return &list.insert(std::forward<Key>(item));
374  }
375 
376  resize(BaseArray::get_capacity() * 2);
377  i = h(item);
378  ++num_items;
379  return &BaseArray::at(i).insert(std::forward<Key>(item));
380  }
381 
382  Key * append(const Key & k)
383  {
384  return insert(k);
385  }
386 
387  Key * append(Key && k)
388  {
389  return insert(std::forward<Key>(k));
390  }
391 
392  Key * append_dup(const Key & k)
393  {
394  return insert_dup(k);
395  }
396 
397  Key * append_dup(Key && k)
398  {
399  return insert_dup(std::forward<Key>(k));
400  }
401 
402  Key * search(const Key & k)
403  {
404  nat_t i = h(k);
405 
406  List & list = BaseArray::at(i);
407 
408  if (list.is_empty())
409  return nullptr;
410 
411  return search_in_list(list, k);
412  }
413 
414  const Key * search(const Key & k) const
415  {
416  nat_t i = h(k);
417 
418  const List & list = BaseArray::at(i);
419 
420  if (list.is_empty())
421  return nullptr;
422 
423  return search_in_list(list, k);
424  }
425 
426  Key * search_or_insert(const Key & item)
427  {
428  nat_t i = h(item);
429 
430  List & list = BaseArray::at(i);
431 
432  if (not list.is_empty())
433  {
434  Key * result = search_in_list(list, item);
435 
436  if (result != nullptr)
437  return result;
438  }
439 
440  if (alpha() < upper_alpha)
441  {
442  ++num_items;
443  return &list.insert(item);
444  }
445 
446  resize(BaseArray::get_capacity() * 2);
447  i = h(item);
448  ++num_items;
449  return &BaseArray::at(i).insert(item);
450  }
451 
452  Key * search_or_insert(Key && item)
453  {
454  nat_t i = h(item);
455 
456  List & list = BaseArray::at(i);
457 
458  if (not list.is_empty())
459  {
460  Key * result = search_in_list(list, item);
461 
462  if (result != nullptr)
463  return result;
464  }
465 
466  if (alpha() < upper_alpha)
467  {
468  ++num_items;
469  return &list.insert(std::forward<Key>(item));
470  }
471 
472  resize(BaseArray::get_capacity() * 2);
473  i = h(item);
474  ++num_items;
475  return &BaseArray::at(i).insert(std::forward<Key>(item));
476  }
477 
478  Key & find(const Key & k)
479  {
480  Key * ptr = search(k);
481 
482  if (ptr == nullptr)
483  throw std::domain_error("Key does not exists");
484 
485  return *ptr;
486  }
487 
488  const Key & find(const Key & k) const
489  {
490  const Key * ptr = search(k);
491 
492  if (ptr == nullptr)
493  throw std::domain_error("Key does not exists");
494 
495  return *ptr;
496  }
497 
498  bool remove(const Key & k)
499  {
500  nat_t i = h(k);
501 
502  List & list = BaseArray::at(i);
503 
504  if (list.is_empty())
505  return false;
506 
507  bool result = list.remove_first_if([&k, this](const auto & item)
508  {
509  return cmp(k, item);
510  });
511 
512  if (not result)
513  return false;
514 
515  --num_items;
516 
517  nat_t min_size = DFT_SIZE;
518 
519  if (BaseArray::get_capacity() == min_size or alpha() > lower_alpha)
520  return true;
521 
522  nat_t new_size = std::max(min_size, BaseArray::get_capacity() / 2);
523  resize(new_size);
524 
525  return true;
526  }
527 
528  class Iterator : public BidirectionalIterator<Iterator, Key>
529  {
530  friend class LHashTable;
531  friend class BasicIterator<Iterator, Key>;
532 
533  LHashTable * set_ptr;
534  lint_t set_pos;
535  typename List::Iterator list_it;
536  lint_t pos;
537 
538  void locate_end();
539 
540  void locate_prev(nat_t);
541 
542  void locate_next(nat_t);
543 
544  protected:
546  {
547  return pos;
548  }
549 
550  Iterator(const LHashTable & h, int)
551  : set_ptr(&const_cast<LHashTable &>(h)), set_pos(h.M()),
552  list_it(), pos(h.N())
553  {
554  locate_end();
555  }
556 
557  public:
559  : set_ptr(nullptr), set_pos(-1), list_it(), pos(-1)
560  {
561  // empty
562  }
563 
564  Iterator(const LHashTable & h)
565  : set_ptr(&const_cast<LHashTable &>(h)), set_pos(0), list_it(), pos(0)
566  {
567  locate_next(set_pos);
568  }
569 
570  Iterator(const Iterator & it)
571  : set_ptr(it.set_ptr), set_pos(it.set_pos), list_it(it.list_it),
572  pos(it.pos)
573  {
574  // empty
575  }
576 
578  : Iterator()
579  {
580  swap(it);
581  }
582 
584  {
585  if (this == &it)
586  return *this;
587 
588  set_ptr = it.set_ptr;
589  set_pos = it.set_pos;
590  list_it = it.list_it;
591  pos = it.pos;
592 
593  return *this;
594  }
595 
597  {
598  swap(it);
599  return *this;
600  }
601 
602  void swap(Iterator & it)
603  {
604  std::swap(set_ptr, it.set_ptr);
605  std::swap(set_pos, it.set_pos);
606  std::swap(list_it, it.list_it);
607  std::swap(pos, it.pos);
608  }
609 
610  void reset()
611  {
612  pos = 0;
613  locate_next(0);
614  }
615 
617  {
618  return pos;
619  }
620 
621  bool has_current() const
622  {
623  return set_pos >= 0 and set_pos < set_ptr->get_capacity();
624  }
625 
626  Key & get_current()
627  {
628  if (not has_current())
629  throw std::overflow_error("There is not current element");
630 
631  return list_it.get_current();
632  }
633 
634  const Key & get_current() const
635  {
636  if (not has_current())
637  throw std::overflow_error("There is not current element");
638 
639  return list_it.get_current();
640  }
641 
642  void next()
643  {
644  if (not has_current())
645  return;
646 
647  ++pos;
648 
649  list_it.next();
650 
651  if (not list_it.has_current())
652  locate_next(set_pos + 1);
653  }
654 
655  void prev()
656  {
657  if (pos == 0)
658  return;
659 
660  --pos;
661 
662  if (set_pos == set_ptr->M() or list_it == set_ptr->at(set_pos).begin())
663  locate_prev(set_pos);
664 
665  list_it.prev();
666  }
667  };
668 
670  {
671  return Iterator(*this);
672  }
673 
674  Iterator begin() const
675  {
676  return Iterator(*this);
677  }
678 
680  {
681  return Iterator(*this, 0);
682  }
683 
684  Iterator end() const
685  {
686  return Iterator(*this, 0);
687  }
688  };
689 
690  template <typename Key, class Cmp>
692  {
693  for (nat_t i = 0; i < BaseArray::get_capacity(); ++i)
694  BaseArray::at(i).clear();
695  }
696 
697  template <typename Key, class Cmp>
699  {
700  LHashTable new_hash_set(sz, cmp, hash_fct, lower_alpha, upper_alpha);
701 
702  for (Key & item : *this)
703  new_hash_set.append(std::move(item));
704 
705  swap(new_hash_set);
706  }
707 
708  template <typename Key, class Cmp>
709  LHashTable<Key, Cmp>::LHashTable(const std::initializer_list<Key> & l)
710  : LHashTable()
711  {
712  for (const Key & item : l)
713  append(item);
714  }
715 
716  template <typename Key, class Cmp>
718  {
719  while (set_pos > 0 and set_ptr->at(set_pos - 1).is_empty())
720  --set_pos;
721 
722  if (set_pos > 0)
723  list_it = set_ptr->at(set_pos - 1).end();
724 
725  return;
726  }
727 
728  template <typename Key, class Cmp>
730  {
731  if (set_ptr->is_empty())
732  return;
733 
734  while (i < set_ptr->get_capacity() and
735  set_ptr->at(i).is_empty())
736  ++i;
737 
738  if (i < set_ptr->get_capacity())
739  {
740  assert(not set_ptr->at(i).is_empty());
741  list_it = set_ptr->at(i).begin();
742  }
743 
744  set_pos = i;
745  }
746 
747  template <typename Key, class Cmp>
749  {
750  if (set_ptr->is_empty())
751  return;
752 
753  while (i > 0 and set_ptr->at(i - 1).is_empty())
754  --i;
755 
756  if (i > 0)
757  {
758  assert(not set_ptr->at(i - 1).is_empty());
759  list_it = set_ptr->at(i - 1).end();
760  }
761 
762  set_pos = i - 1;
763  }
764 
765 } // end namespace Designar
766 
767 # endif // DSGHASH_H
LHashTable(LHashTable &&h)
Definition: hash.H:192
Iterator(const Iterator &it)
Definition: hash.H:570
Key * append_dup(Key &&k)
Definition: hash.H:397
Key * search_or_insert(const Key &item)
Definition: hash.H:426
nat_t(*)(const MapKey< T, nat_t > &) HashFctPtr
Definition: hash.H:87
LHashTable(nat_t size, Cmp &_cmp, HashFctPtr fct=&super_fast_hash)
Definition: hash.H:148
LHashTable(nat_t size, Cmp &&_cmp=Cmp(), HashFctPtr fct=&super_fast_hash)
Definition: hash.H:154
void set_lower_alpha(real_t value)
Definition: hash.H:256
const Key & find(const Key &k) const
Definition: hash.H:488
Iterator()
Definition: hash.H:558
nat_t size() const
Definition: hash.H:282
bool is_empty() const
Definition: nodesdef.H:153
LHashTable(const LHashTable &h)
Definition: hash.H:185
Key * insert_dup(const Key &item)
Definition: hash.H:346
Definition: setalgorithms.H:36
Key * search(const Key &k)
Definition: hash.H:402
double real_t
Definition: types.H:51
void next()
Definition: nodesdef.H:383
LHashTable(Cmp &_cmp, HashFctType fct)
Definition: hash.H:161
std::function< nat_t(const MapKey< T, nat_t > &)> HashFctType
Definition: hash.H:88
Iterator(Iterator &&it)
Definition: hash.H:577
const Cmp & get_cmp() const
Definition: hash.H:236
Iterator end() const
Definition: hash.H:684
Definition: iterator.H:36
Key * insert_dup(Key &&item)
Definition: hash.H:364
Key & get_current()
Definition: hash.H:626
Key & find(const Key &k)
Definition: hash.H:478
lint_t get_position() const
Definition: hash.H:616
Key * append_dup(const Key &k)
Definition: hash.H:392
nat_t M() const
Definition: hash.H:292
Iterator & operator=(const Iterator &it)
Definition: hash.H:583
void clear()
Definition: hash.H:297
Iterator end()
Definition: hash.H:679
Iterator(const LHashTable &h)
Definition: hash.H:564
Definition: hash.H:73
bool is_empty() const
Definition: hash.H:277
Definition: hash.H:528
real_t get_upper_alpha() const
Definition: hash.H:251
nat_t N() const
Definition: hash.H:287
void reset()
Definition: hash.H:610
const Key * search(const Key &k) const
Definition: hash.H:414
static constexpr nat_t DFT_SIZE
Definition: hash.H:90
nat_t super_fast_hash(void *, nat_t)
Key * append(Key &&k)
Definition: hash.H:387
Key & key(MapKey< Key, Value > &item)
Definition: map.H:53
LHashTable(nat_t size, Cmp &_cmp, HashFctType fct)
Definition: hash.H:136
void swap(FixedArray &a)
Definition: array.H:258
Key * insert(Key &&item)
Definition: hash.H:325
LHashTable(nat_t size, Cmp &&_cmp, HashFctType fct)
Definition: hash.H:142
bool remove_first_if(Pred &pred)
Definition: containeralgorithms.H:213
real_t alpha() const
Definition: hash.H:272
Iterator begin()
Definition: hash.H:669
bool has_current() const
Definition: nodesdef.H:362
Key * insert(const Key &item)
Definition: hash.H:304
long long lint_t
Definition: types.H:49
T & insert(const T &item)
Definition: list.H:663
LHashTable & operator=(const LHashTable &h)
Definition: hash.H:200
void set_upper_alpha(real_t value)
Definition: hash.H:261
Iterator begin() const
Definition: hash.H:674
LHashTable(nat_t size, Cmp &_cmp, HashFctType fct, real_t _lower_alpha, real_t _upper_alpha)
Definition: hash.H:128
void swap(LHashTable &h)
Definition: hash.H:221
Definition: containeralgorithms.H:33
Key * append(const Key &k)
Definition: hash.H:382
real_t get_lower_alpha() const
Definition: hash.H:246
void prev()
Definition: hash.H:655
T & append(const T &item)
Definition: list.H:679
void swap(Iterator &it)
Definition: hash.H:602
LHashTable(Cmp &&_cmp, HashFctType fct)
Definition: hash.H:167
void next()
Definition: hash.H:642
Definition: array.H:182
const Key & get_current() const
Definition: hash.H:634
Key * search_or_insert(Key &&item)
Definition: hash.H:452
Definition: iterator.H:112
Definition: array.H:32
nat_t get_capacity() const
Definition: array.H:266
T * search_ptr(Pred &pred) const
Definition: containeralgorithms.H:200
Iterator begin()
Definition: list.H:883
unsigned long int nat_t
Definition: types.H:50
LHashTable(Cmp &&_cmp=Cmp(), HashFctPtr fct=&super_fast_hash)
Definition: hash.H:179
Value & value(MapKey< Key, Value > &item)
Definition: map.H:77
LHashTable(Cmp &_cmp, HashFctPtr fct=&super_fast_hash)
Definition: hash.H:173
Iterator end()
Definition: list.H:893
Iterator(const LHashTable &h, int)
Definition: hash.H:550
void reset_alpha_values()
Definition: hash.H:266
bool has_current() const
Definition: hash.H:621
static constexpr real_t DFT_LOWER_ALPHA
Definition: hash.H:91
lint_t get_location() const
Definition: hash.H:545
DL * get_current()
Definition: nodesdef.H:367
Cmp & get_cmp()
Definition: hash.H:231
static constexpr real_t DFT_UPPER_ALPHA
Definition: hash.H:92
T & at(nat_t i)
Definition: array.H:276
const HashFctType & get_hash_fct() const
Definition: hash.H:241
Definition: nodesdef.H:293