Aleph-w  1.9
General library for algorithms and data structures
tpl_olhash.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 
28 # ifndef TPL_OLHASH_H
29 # define TPL_OLHASH_H
30 
31 # include <iostream>
32 # include <primes.H>
33 # include <dlink.H>
34 # include <ahDry.H>
35 # include <hash-dry.H>
36 # include <hashDry.H>
37 # include <hash-fct.H>
38 
39 
40 using namespace Primes;
41 
42 using namespace Aleph;
43 
44 # ifdef N
45 # define NBACKUP N
46 # undef N
47 # endif
48 
49 # ifdef M
50 # define MBACKUP M
51 # undef M
52 # endif
53 
54 namespace Aleph {
55 
72  template <typename Key, class Cmp = Aleph::equal_to<Key>>
74  : public OhashCommon<OLhashTable<Key, Cmp>, Key>,
75  public GenericTraverse<OLhashTable<Key, Cmp>>,
76  public LocateFunctions<OLhashTable<Key, Cmp>, Key>,
77  public FunctionalMethods<OLhashTable<Key, Cmp>, Key>,
78  public EqualToMethod<OLhashTable<Key, Cmp>>,
79  public StlAlephIterator<OLhashTable<Key, Cmp>>
80 {
81  friend class OhashCommon<OLhashTable<Key, Cmp>, Key>;
82 
83 public:
84 
85  using Key_Type = Key;
86 
87  using Item_Type = Key;
88 
89  using Hash_Fct = std::function<size_t(const Key &)>;
90 
91  using Hash_Fct_Ptr = size_t (*) (const Key&);
92 
93  enum Status { EMPTY, BUSY, DELETED };
94 
95  struct Bucket
96  {
97  Key key;
98  char status = EMPTY;
99 
100  Bucket() noexcept : status(EMPTY) {}
101  void reset() noexcept { status = EMPTY; }
102  };
103 
104  static Bucket * key_to_bucket(Key * rec) noexcept
105  {
106  Bucket * ret_val = 0;
107  long offset = (long) &ret_val->key;
108  return (Bucket*) ((long) rec - offset);
109  }
110 
111  Bucket * table = nullptr;
112  size_t N = 0;
113 
114 protected:
115 
116  size_t len;
117  float lower_alpha;
118  float upper_alpha;
119  Cmp cmp;
120 
121 private:
122 
123  Hash_Fct hash_fct;
124  bool with_resize;
125 
126  bool is_valid_bucket(Bucket * bucket) const noexcept
127  {
128  if (bucket < &table[0] or bucket >= &table[len])
129  return false;
130 
131  int offset_with_base = (char*) bucket - (char*) &table[0];
132 
133  return offset_with_base % sizeof(*bucket) == 0;
134  }
135 
136 public:
137 
138  const Cmp & get_compare() const { return cmp; }
139 
140  Cmp & get_compare() { return cmp; }
141 
142  protected:
143 
146  OLhashTable(size_t __len, Hash_Fct __hash_fct, Cmp __cmp,
147  float __lower_alpha, float __upper_alpha, bool __with_resize)
148  : table(nullptr), N(0), len(Primes::next_prime(__len)),
149  lower_alpha(__lower_alpha), upper_alpha(__upper_alpha), cmp(__cmp),
150  hash_fct(__hash_fct), with_resize(__with_resize)
151  {
152  table = new Bucket [len];
153  }
154 
155  OLhashTable(size_t len, Hash_Fct hash_fct, Hash_Fct, Cmp cmp,
156  float lower_alpha, float upper_alpha, bool with_resize)
157  : OLhashTable(len, hash_fct, cmp, lower_alpha, upper_alpha, with_resize) {}
158 
159  public:
160 
161  OLhashTable(size_t len = Primes::DefaultPrime,
162  Hash_Fct_Ptr hash_fct = Aleph::dft_hash_fct<Key>,
163  Cmp cmp = Cmp(),
164  float lower_alpha = hash_default_lower_alpha,
165  float upper_alpha = hash_default_upper_alpha,
166  bool with_resize = true)
167  : OLhashTable(len, Hash_Fct(hash_fct), cmp,
168  lower_alpha, upper_alpha, with_resize) {}
169 
170  OLhashTable(size_t len, Hash_Fct_Ptr hash_fct, Hash_Fct_Ptr,
171  Cmp cmp, float lower_alpha, float upper_alpha, bool with_resize)
172  : OLhashTable(len, Hash_fct(hash_fct), cmp,
173  lower_alpha, upper_alpha, with_resize) {}
174 
178  OLhashTable(size_t len, Hash_Fct hash_fct, Hash_Fct_Ptr, Cmp cmp,
179  float lower_alpha, float upper_alpha, bool with_resize)
180  : OLhashTable(len, hash_fct, cmp,
181  lower_alpha, upper_alpha, with_resize) {}
182 
183  Special_Ctors(OLhashTable, Key);
184 
187  {
188  if (table != nullptr)
189  delete [] table;
190  }
191 
192  void swap(OLhashTable & other) noexcept
193  {
194  std::swap(table, other.table);
195  std::swap(N, other.N);
196  std::swap(len, other.len);
197  std::swap(cmp, other.cmp);
198  std::swap(hash_fct, other.hash_fct);
199  std::swap(lower_alpha, other.lower_alpha);
200  std::swap(upper_alpha, other.upper_alpha);
201  std::swap(with_resize, other.with_resize);
202  }
203 
204  OLhashTable(const OLhashTable & other)
205  : OLhashTable(other.len, other.hash_fct, other.cmp,
206  other.lower_alpha, other.upper_alpha, other.with_resize)
207  {
208  this->copy_from_table(other);
209  }
210 
211  OLhashTable(OLhashTable && other) noexcept : OLhashTable(other)
212  {
213  swap(other);
214  }
215 
216  OLhashTable & operator = (const OLhashTable & other)
217  {
218  if (this == &other)
219  return *this;
220 
221  if (len > other.N)
222  this->clean_table();
223  else
224  {
225  Bucket * new_table = new Bucket [other.len];
226  delete [] table;
227  table = new_table;
228  N = 0;
229  len = other.len;
230  hash_fct = other.hash_fct;
231  cmp = other.cmp;
232  lower_alpha = other.lower_alpha;
233  upper_alpha = other.upper_alpha;
234  }
235 
236  this->copy_from_table(other);
237 
238  return *this;
239  }
240 
241  OLhashTable & operator = (OLhashTable && other) noexcept
242  {
243  swap(other);
244  return *this;
245  }
246 
249  Key * search(const Key & key) const noexcept
250  {
251  long i = hash_fct(key) % len, c = 0;
252  while (c < len and table[i].status != EMPTY)
253  {
254  if (table[i].status == BUSY and cmp(table[i].key, key))
255  return &table[i].key;
256 
257  ++c;
258  if (++i == len)
259  i = 0;
260  }
261 
262  return nullptr; // No se encuentra la clave
263  }
264 
265 protected:
266 
267  Bucket * allocate_bucket(const Key & key) noexcept
268  {
269  assert(N < len);
270 
271  size_t i = hash_fct(key) % len;
272 
273  while (table[i].status == BUSY) // find a slot that is not busy
274  {
275  if (cmp(key, table[i].key))
276  return nullptr;
277 
278  if (++i == len)
279  i = 0;
280  }
281 
282  Bucket * bucket = &table[i];
283 
284  // i contiene celda con DELETED o EMPTY ==> ocuparla
285  bucket->status = BUSY;
286  N++;
287 
288  return bucket;
289  }
290 
291  tuple<Bucket*, bool> hard_allocate_bucket(const Key & key) noexcept
292  {
293  assert(N < len);
294 
295  size_t i = hash_fct(key) % len;
296  while (table[i].status == BUSY) // find a slot that is not busy
297  {
298  if (cmp(key, table[i].key))
299  return make_tuple(&table[i], true);
300 
301  if (++i == len)
302  i = 0;
303  }
304 
305  Bucket * bucket = &table[i];
306 
307  // i contiene celda con DELETED o EMPTY ==> ocuparla
308  bucket->status = BUSY;
309  N++;
310 
311  return make_tuple(bucket, false);
312  }
313 
319  void deallocate_bucket(Bucket * bucket)
320  {
321  if (not is_valid_bucket(bucket))
322  throw std::invalid_argument("record address is not inside table's range");
323 
324  if (bucket->status != BUSY)
325  throw std::domain_error("Bucket containing record is not busy");
326 
327  --N;
328  int i = bucket - &table[0]; // índice de brecha
329  table[i].status = DELETED;
330  }
331 
332  public:
333 
334 
339  void remove(const Key & key)
340  {
341  Key * key_ptr = search(key);
342  if (key_ptr == nullptr)
343  throw std::domain_error("Key not in hash table");
344 
345  this->remove_ptr(key_ptr);
346  }
347 
348  OHASH_COMMON(OLhashTable);
349 
350  using Stats = typename OhashCommon<OLhashTable<Key, Cmp>, Key>::Stats;
351 
352  Stats stats() const
353  {
354  DynArray<size_t> lens;
355  size_t num_busy = 0, num_deleted = 0, num_empty = 0;
356  size_t max_len = std::numeric_limits<size_t>::min();
357  for (int i = 0; i < len; ++i)
358  switch (table[i].status)
359  {
360  case BUSY:
361  {
362  ++num_busy;
363  const Key & key = table[i].key;
364  long i = hash_fct(key) % len;
365  size_t count = 1;
366 
367  while (true)
368  {
369  if (table[i].status == BUSY and cmp(table[i].key, key))
370  break;
371  ++count;
372  if (++i == len)
373  i = 0;
374  }
375 
376  max_len = std::max(max_len, count);
377  update_stat_len(lens, count);
378  break;
379  }
380  case EMPTY:
381  ++num_empty;
382  update_stat_len(lens, 0);
383  break;
384  case DELETED:
385  ++num_deleted;
386  break;
387  }
388 
389  float avg = 0, sum = 0;
390  for (int i = 0; i < lens.size(); ++i)
391  {
392  avg += lens(i)*i;
393  sum += lens(i);
394  }
395 
396  avg /= sum;
397  float var = 0;
398  for (int i = 0; i < lens.size(); ++i)
399  {
400  float s = i - avg;
401  var += lens(i)*s*s;
402  }
403  var /= sum;
404 
405  Stats stats;
406  stats.num_busy = num_busy;
407  stats.num_deleted = num_deleted;
408  stats.num_empty = num_empty;
409  std::swap(lens, stats.lens);
410  stats.avg = avg;
411  stats.var = var;
412  stats.max_len = max_len;
413 
414  return stats;
415  }
416 };
417 
418 
419 
420 template <typename Key, class Cmp = Aleph::equal_to<Key>>
422 
423 
424 }
425 # endif // TPL_OLHASH_H
426 
Definition: htlist.H:450
Definition: htlist.H:133
OLhashTable(size_t len, Hash_Fct hash_fct, Hash_Fct_Ptr, Cmp cmp, float lower_alpha, float upper_alpha, bool with_resize)
Definition: tpl_olhash.H:178
Definition: htlist.H:45
Definition: ah-comb.H:35
Key * search(const Key &key) const noexcept
Definition: tpl_olhash.H:249
size_t size() const noexcept
Definition: tpl_dynArray.H:641
~OLhashTable()
Libera toda la memoria ocupada.
Definition: tpl_olhash.H:186
OLhashTable(size_t __len, Hash_Fct __hash_fct, Cmp __cmp, float __lower_alpha, float __upper_alpha, bool __with_resize)
Definition: tpl_olhash.H:146
Definition: primes.H:33
Definition: htlist.H:1323
void deallocate_bucket(Bucket *bucket)
Definition: tpl_olhash.H:319
Definition: tpl_olhash.H:73

Leandro Rabindranath León