libstdc++
gp_ht_map_.hpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 
3 // Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the terms
8 // of the GNU General Public License as published by the Free Software
9 // Foundation; either version 3, or (at your option) any later
10 // version.
11 
12 // This library is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
27 
28 // Permission to use, copy, modify, sell, and distribute this software
29 // is hereby granted without fee, provided that the above copyright
30 // notice appears in all copies, and that both that copyright notice
31 // and this permission notice appear in supporting documentation. None
32 // of the above authors, nor IBM Haifa Research Laboratories, make any
33 // representation about the suitability of this software for any
34 // purpose. It is provided "as is" without express or implied
35 // warranty.
36 
37 /**
38  * @file gp_hash_table_map_/gp_ht_map_.hpp
39  * Contains an implementation class for general probing hash.
40  */
41 
45 #include <ext/pb_ds/exception.hpp>
47 #include <utility>
48 #ifdef PB_DS_HT_MAP_TRACE_
49 #include <iostream>
50 #endif
51 #ifdef _GLIBCXX_DEBUG
53 #endif
54 #include <debug/debug.h>
55 
56 namespace __gnu_pbds
57 {
58  namespace detail
59  {
60 #ifdef PB_DS_DATA_TRUE_INDICATOR
61 #define PB_DS_GP_HASH_NAME gp_ht_map
62 #endif
63 
64 #ifdef PB_DS_DATA_FALSE_INDICATOR
65 #define PB_DS_GP_HASH_NAME gp_ht_set
66 #endif
67 
68 #define PB_DS_CLASS_T_DEC \
69  template<typename Key, typename Mapped, typename Hash_Fn, typename Eq_Fn, \
70  typename _Alloc, bool Store_Hash, typename Comb_Probe_Fn, \
71  typename Probe_Fn, typename Resize_Policy>
72 
73 #define PB_DS_CLASS_C_DEC \
74  PB_DS_GP_HASH_NAME<Key, Mapped, Hash_Fn, Eq_Fn, _Alloc, \
75  Store_Hash, Comb_Probe_Fn, Probe_Fn, Resize_Policy>
76 
77 #define PB_DS_HASH_EQ_FN_C_DEC \
78  hash_eq_fn<Key, Eq_Fn, _Alloc, Store_Hash>
79 
80 #define PB_DS_RANGED_PROBE_FN_C_DEC \
81  ranged_probe_fn<Key, Hash_Fn, _Alloc, Comb_Probe_Fn, Probe_Fn, Store_Hash>
82 
83 #define PB_DS_GP_HASH_TRAITS_BASE \
84  types_traits<Key, Mapped, _Alloc, Store_Hash>
85 
86 #ifdef _GLIBCXX_DEBUG
87 #define PB_DS_DEBUG_MAP_BASE_C_DEC \
88  debug_map_base<Key, Eq_Fn, \
89  typename _Alloc::template rebind<Key>::other::const_reference>
90 #endif
91 
92 
93  /**
94  * A general-probing hash-based container.
95  *
96  *
97  * @ingroup hash-detail
98  *
99  * @tparam Key Key type.
100  *
101  * @tparam Mapped Map type.
102  *
103  * @tparam Hash_Fn Hashing functor.
104  * Default is __gnu_cxx::hash.
105  *
106  * @tparam Eq_Fn Equal functor.
107  * Default std::equal_to<Key>
108  *
109  * @tparam _Alloc Allocator type.
110  *
111  * @tparam Store_Hash If key type stores extra metadata.
112  * Defaults to false.
113  *
114  * @tparam Comb_Probe_Fn Combining probe functor.
115  * If Hash_Fn is not null_type, then this
116  * is the ranged-probe functor; otherwise,
117  * this is the range-hashing functor.
118  * XXX See Design::Hash-Based Containers::Hash Policies.
119  * Default direct_mask_range_hashing.
120  *
121  * @tparam Probe_Fn Probe functor.
122  * Defaults to linear_probe_fn,
123  * also quadratic_probe_fn.
124  *
125  * @tparam Resize_Policy Resizes hash.
126  * Defaults to hash_standard_resize_policy,
127  * using hash_exponential_size_policy and
128  * hash_load_check_resize_trigger.
129  *
130  *
131  * Bases are: detail::hash_eq_fn, Resize_Policy, detail::ranged_probe_fn,
132  * detail::types_traits. (Optional: detail::debug_map_base.)
133  */
134  template<typename Key,
135  typename Mapped,
136  typename Hash_Fn,
137  typename Eq_Fn,
138  typename _Alloc,
139  bool Store_Hash,
140  typename Comb_Probe_Fn,
141  typename Probe_Fn,
142  typename Resize_Policy>
143  class PB_DS_GP_HASH_NAME :
144 #ifdef _GLIBCXX_DEBUG
145  protected PB_DS_DEBUG_MAP_BASE_C_DEC,
146 #endif
147  public PB_DS_HASH_EQ_FN_C_DEC,
148  public Resize_Policy,
149  public PB_DS_RANGED_PROBE_FN_C_DEC,
150  public PB_DS_GP_HASH_TRAITS_BASE
151  {
152  private:
153  typedef PB_DS_GP_HASH_TRAITS_BASE traits_base;
154  typedef typename traits_base::value_type value_type_;
155  typedef typename traits_base::pointer pointer_;
156  typedef typename traits_base::const_pointer const_pointer_;
157  typedef typename traits_base::reference reference_;
158  typedef typename traits_base::const_reference const_reference_;
159  typedef typename traits_base::comp_hash comp_hash;
160 
161  enum entry_status
162  {
163  empty_entry_status,
164  valid_entry_status,
165  erased_entry_status
166  } __attribute__ ((packed));
167 
168  struct entry : public traits_base::stored_data_type
169  {
170  entry_status m_stat;
171  };
172 
173  typedef typename _Alloc::template rebind<entry>::other entry_allocator;
174  typedef typename entry_allocator::pointer entry_pointer;
175  typedef typename entry_allocator::const_pointer const_entry_pointer;
176  typedef typename entry_allocator::reference entry_reference;
177  typedef typename entry_allocator::const_reference const_entry_reference;
178  typedef typename entry_allocator::pointer entry_array;
179 
180  typedef PB_DS_RANGED_PROBE_FN_C_DEC ranged_probe_fn_base;
181 
182 #ifdef _GLIBCXX_DEBUG
183  typedef PB_DS_DEBUG_MAP_BASE_C_DEC debug_base;
184 #endif
185 
186  typedef PB_DS_HASH_EQ_FN_C_DEC hash_eq_fn_base;
187  typedef Resize_Policy resize_base;
188 
189 #define PB_DS_GEN_POS typename _Alloc::size_type
190 
195 
196 #undef PB_DS_GEN_POS
197 
198  public:
199  typedef _Alloc allocator_type;
200  typedef typename _Alloc::size_type size_type;
201  typedef typename _Alloc::difference_type difference_type;
202  typedef Hash_Fn hash_fn;
203  typedef Eq_Fn eq_fn;
204  typedef Probe_Fn probe_fn;
205  typedef Comb_Probe_Fn comb_probe_fn;
206  typedef Resize_Policy resize_policy;
207 
208  /// Value stores hash, true or false.
209  enum
210  {
211  store_hash = Store_Hash
212  };
213 
214  typedef typename traits_base::key_type key_type;
215  typedef typename traits_base::key_pointer key_pointer;
216  typedef typename traits_base::key_const_pointer key_const_pointer;
217  typedef typename traits_base::key_reference key_reference;
218  typedef typename traits_base::key_const_reference key_const_reference;
219  typedef typename traits_base::mapped_type mapped_type;
220  typedef typename traits_base::mapped_pointer mapped_pointer;
221  typedef typename traits_base::mapped_const_pointer mapped_const_pointer;
222  typedef typename traits_base::mapped_reference mapped_reference;
223  typedef typename traits_base::mapped_const_reference mapped_const_reference;
224  typedef typename traits_base::value_type value_type;
225  typedef typename traits_base::pointer pointer;
226  typedef typename traits_base::const_pointer const_pointer;
227  typedef typename traits_base::reference reference;
228  typedef typename traits_base::const_reference const_reference;
229 
230 #ifdef PB_DS_DATA_TRUE_INDICATOR
231  typedef point_iterator_ point_iterator;
232 #endif
233 
234 #ifdef PB_DS_DATA_FALSE_INDICATOR
235  typedef point_const_iterator_ point_iterator;
236 #endif
237 
238  typedef point_const_iterator_ point_const_iterator;
239 
240 #ifdef PB_DS_DATA_TRUE_INDICATOR
241  typedef iterator_ iterator;
242 #endif
243 
244 #ifdef PB_DS_DATA_FALSE_INDICATOR
245  typedef const_iterator_ iterator;
246 #endif
247 
248  typedef const_iterator_ const_iterator;
249 
250  PB_DS_GP_HASH_NAME();
251 
252  PB_DS_GP_HASH_NAME(const PB_DS_CLASS_C_DEC&);
253 
254  PB_DS_GP_HASH_NAME(const Hash_Fn&);
255 
256  PB_DS_GP_HASH_NAME(const Hash_Fn&, const Eq_Fn&);
257 
258  PB_DS_GP_HASH_NAME(const Hash_Fn&, const Eq_Fn&, const Comb_Probe_Fn&);
259 
260  PB_DS_GP_HASH_NAME(const Hash_Fn&, const Eq_Fn&, const Comb_Probe_Fn&,
261  const Probe_Fn&);
262 
263  PB_DS_GP_HASH_NAME(const Hash_Fn&, const Eq_Fn&, const Comb_Probe_Fn&,
264  const Probe_Fn&, const Resize_Policy&);
265 
266  template<typename It>
267  void
268  copy_from_range(It, It);
269 
270  virtual
271  ~PB_DS_GP_HASH_NAME();
272 
273  void
274  swap(PB_DS_CLASS_C_DEC&);
275 
276  inline size_type
277  size() const;
278 
279  inline size_type
280  max_size() const;
281 
282  /// True if size() == 0.
283  inline bool
284  empty() const;
285 
286  /// Return current hash_fn.
287  Hash_Fn&
288  get_hash_fn();
289 
290  /// Return current const hash_fn.
291  const Hash_Fn&
292  get_hash_fn() const;
293 
294  /// Return current eq_fn.
295  Eq_Fn&
296  get_eq_fn();
297 
298  /// Return current const eq_fn.
299  const Eq_Fn&
300  get_eq_fn() const;
301 
302  /// Return current probe_fn.
303  Probe_Fn&
304  get_probe_fn();
305 
306  /// Return current const probe_fn.
307  const Probe_Fn&
308  get_probe_fn() const;
309 
310  /// Return current comb_probe_fn.
311  Comb_Probe_Fn&
312  get_comb_probe_fn();
313 
314  /// Return current const comb_probe_fn.
315  const Comb_Probe_Fn&
316  get_comb_probe_fn() const;
317 
318  /// Return current resize_policy.
319  Resize_Policy&
320  get_resize_policy();
321 
322  /// Return current const resize_policy.
323  const Resize_Policy&
324  get_resize_policy() const;
325 
327  insert(const_reference r_val)
328  {
329  _GLIBCXX_DEBUG_ONLY(PB_DS_CLASS_C_DEC::assert_valid(__FILE__, __LINE__);)
330  return insert_imp(r_val, traits_base::m_store_extra_indicator);
331  }
332 
333  inline mapped_reference
334  operator[](key_const_reference r_key)
335  {
336 #ifdef PB_DS_DATA_TRUE_INDICATOR
337  return subscript_imp(r_key, traits_base::m_store_extra_indicator);
338 #else
339  insert(r_key);
340  return traits_base::s_null_type;
341 #endif
342  }
343 
344  inline point_iterator
345  find(key_const_reference);
346 
347  inline point_const_iterator
348  find(key_const_reference) const;
349 
350  inline point_iterator
351  find_end();
352 
353  inline point_const_iterator
354  find_end() const;
355 
356  inline bool
357  erase(key_const_reference);
358 
359  template<typename Pred>
360  inline size_type
361  erase_if(Pred);
362 
363  void
364  clear();
365 
366  inline iterator
367  begin();
368 
369  inline const_iterator
370  begin() const;
371 
372  inline iterator
373  end();
374 
375  inline const_iterator
376  end() const;
377 
378 #ifdef _GLIBCXX_DEBUG
379  void
380  assert_valid(const char*, int) const;
381 #endif
382 
383 #ifdef PB_DS_HT_MAP_TRACE_
384  void
385  trace() const;
386 #endif
387 
388  private:
389 #ifdef PB_DS_DATA_TRUE_INDICATOR
390  friend class iterator_;
391 #endif
392 
393  friend class const_iterator_;
394 
395  void
396  deallocate_all();
397 
398  void
399  initialize();
400 
401  void
402  erase_all_valid_entries(entry_array, size_type);
403 
404  inline bool
405  do_resize_if_needed();
406 
407  inline void
408  do_resize_if_needed_no_throw();
409 
410  void
411  resize_imp(size_type);
412 
413  virtual void
414  do_resize(size_type);
415 
416  void
417  resize_imp(entry_array, size_type);
418 
419  inline void
420  resize_imp_reassign(entry_pointer, entry_array, false_type);
421 
422  inline void
423  resize_imp_reassign(entry_pointer, entry_array, true_type);
424 
425  inline size_type
426  find_ins_pos(key_const_reference, false_type);
427 
428  inline comp_hash
429  find_ins_pos(key_const_reference, true_type);
430 
432  insert_imp(const_reference, false_type);
433 
435  insert_imp(const_reference, true_type);
436 
437  inline pointer
438  insert_new_imp(const_reference r_val, size_type pos)
439  {
440  _GLIBCXX_DEBUG_ASSERT(m_entries[pos].m_stat != valid_entry_status);
441 
442  if (do_resize_if_needed())
443  pos = find_ins_pos(PB_DS_V2F(r_val),
444  traits_base::m_store_extra_indicator);
445 
446  _GLIBCXX_DEBUG_ASSERT(m_entries[pos].m_stat != valid_entry_status);
447  entry* const p_e = m_entries + pos;
448  new (&p_e->m_value) value_type(r_val);
449  p_e->m_stat = valid_entry_status;
450  resize_base::notify_inserted(++m_num_used_e);
451 
452  _GLIBCXX_DEBUG_ONLY(debug_base::insert_new(PB_DS_V2F(p_e->m_value));)
453  _GLIBCXX_DEBUG_ONLY(assert_valid(__FILE__, __LINE__);)
454  return &p_e->m_value;
455  }
456 
457  inline pointer
458  insert_new_imp(const_reference r_val, comp_hash& r_pos_hash_pair)
459  {
460  _GLIBCXX_DEBUG_ASSERT(m_entries[r_pos_hash_pair.first].m_stat !=
461  valid_entry_status);
462 
463  if (do_resize_if_needed())
464  r_pos_hash_pair = find_ins_pos(PB_DS_V2F(r_val),
465  traits_base::m_store_extra_indicator);
466 
467  _GLIBCXX_DEBUG_ASSERT(m_entries[r_pos_hash_pair.first].m_stat !=
468  valid_entry_status);
469 
470  entry* const p_e = m_entries + r_pos_hash_pair.first;
471  new (&p_e->m_value) value_type(r_val);
472  p_e->m_hash = r_pos_hash_pair.second;
473  p_e->m_stat = valid_entry_status;
474 
475  resize_base::notify_inserted(++m_num_used_e);
476 
477  _GLIBCXX_DEBUG_ONLY(debug_base::insert_new(PB_DS_V2F(p_e->m_value));)
478  _GLIBCXX_DEBUG_ONLY(assert_valid(__FILE__, __LINE__);)
479  return &p_e->m_value;
480  }
481 
482 #ifdef PB_DS_DATA_TRUE_INDICATOR
483  inline mapped_reference
484  subscript_imp(key_const_reference key, false_type)
485  {
486  _GLIBCXX_DEBUG_ONLY(assert_valid(__FILE__, __LINE__);)
487 
488  const size_type pos = find_ins_pos(key,
489  traits_base::m_store_extra_indicator);
490 
491  entry_pointer p_e = &m_entries[pos];
492  if (p_e->m_stat != valid_entry_status)
493  return insert_new_imp(value_type(key, mapped_type()), pos)->second;
494 
495  PB_DS_CHECK_KEY_EXISTS(key)
496  return p_e->m_value.second;
497  }
498 
499  inline mapped_reference
500  subscript_imp(key_const_reference key, true_type)
501  {
502  _GLIBCXX_DEBUG_ONLY(assert_valid(__FILE__, __LINE__);)
503 
504  comp_hash pos_hash_pair = find_ins_pos(key,
505  traits_base::m_store_extra_indicator);
506 
507  if (m_entries[pos_hash_pair.first].m_stat != valid_entry_status)
508  return insert_new_imp(value_type(key, mapped_type()),
509  pos_hash_pair)->second;
510 
511  PB_DS_CHECK_KEY_EXISTS(key)
512  return (m_entries + pos_hash_pair.first)->m_value.second;
513  }
514 #endif
515 
516  inline pointer
517  find_key_pointer(key_const_reference key, false_type)
518  {
519  const size_type hash = ranged_probe_fn_base::operator()(key);
520  resize_base::notify_find_search_start();
521 
522  // Loop until entry is found or until all possible entries accessed.
523  for (size_type i = 0; i < m_num_e; ++i)
524  {
525  const size_type pos = ranged_probe_fn_base::operator()(key,
526  hash, i);
527 
528  entry* const p_e = m_entries + pos;
529  switch (p_e->m_stat)
530  {
531  case empty_entry_status:
532  {
533  resize_base::notify_find_search_end();
534  PB_DS_CHECK_KEY_DOES_NOT_EXIST(key)
535  return 0;
536  }
537  break;
538  case valid_entry_status:
539  if (hash_eq_fn_base::operator()(PB_DS_V2F(p_e->m_value), key))
540  {
541  resize_base::notify_find_search_end();
542  PB_DS_CHECK_KEY_EXISTS(key)
543  return pointer(&p_e->m_value);
544  }
545  break;
546  case erased_entry_status:
547  break;
548  default:
549  _GLIBCXX_DEBUG_ASSERT(0);
550  };
551 
552  resize_base::notify_find_search_collision();
553  }
554 
555  PB_DS_CHECK_KEY_DOES_NOT_EXIST(key)
556  resize_base::notify_find_search_end();
557  return 0;
558  }
559 
560  inline pointer
561  find_key_pointer(key_const_reference key, true_type)
562  {
563  comp_hash pos_hash_pair = ranged_probe_fn_base::operator()(key);
564  resize_base::notify_find_search_start();
565 
566  // Loop until entry is found or until all possible entries accessed.
567  for (size_type i = 0; i < m_num_e; ++i)
568  {
569  const size_type pos =
570  ranged_probe_fn_base::operator()(key, pos_hash_pair.second, i);
571 
572  entry* const p_e = m_entries + pos;
573 
574  switch(p_e->m_stat)
575  {
576  case empty_entry_status:
577  {
578  resize_base::notify_find_search_end();
579  PB_DS_CHECK_KEY_DOES_NOT_EXIST(key)
580  return 0;
581  }
582  break;
583  case valid_entry_status:
584  if (hash_eq_fn_base::operator()(PB_DS_V2F(p_e->m_value),
585  p_e->m_hash,
586  key, pos_hash_pair.second))
587  {
588  resize_base::notify_find_search_end();
589  PB_DS_CHECK_KEY_EXISTS(key)
590  return pointer(&p_e->m_value);
591  }
592  break;
593  case erased_entry_status:
594  break;
595  default:
596  _GLIBCXX_DEBUG_ASSERT(0);
597  };
598 
599  resize_base::notify_find_search_collision();
600  }
601 
602  PB_DS_CHECK_KEY_DOES_NOT_EXIST(key)
603  resize_base::notify_find_search_end();
604  return 0;
605  }
606 
607  inline bool
608  erase_imp(key_const_reference, true_type);
609 
610  inline bool
611  erase_imp(key_const_reference, false_type);
612 
613  inline void
614  erase_entry(entry_pointer);
615 
616 #ifdef PB_DS_DATA_TRUE_INDICATOR
617  void
618  inc_it_state(pointer& r_p_value, size_type& r_pos) const
619  { inc_it_state((mapped_const_pointer& )r_p_value, r_pos); }
620 #endif
621 
622  void
623  inc_it_state(const_pointer& r_p_value, size_type& r_pos) const
624  {
625  _GLIBCXX_DEBUG_ASSERT(r_p_value != 0);
626  for (++r_pos; r_pos < m_num_e; ++r_pos)
627  {
628  const_entry_pointer p_e =& m_entries[r_pos];
629  if (p_e->m_stat == valid_entry_status)
630  {
631  r_p_value =& p_e->m_value;
632  return;
633  }
634  }
635  r_p_value = 0;
636  }
637 
638  void
639  get_start_it_state(const_pointer& r_p_value, size_type& r_pos) const
640  {
641  for (r_pos = 0; r_pos < m_num_e; ++r_pos)
642  {
643  const_entry_pointer p_e = &m_entries[r_pos];
644  if (p_e->m_stat == valid_entry_status)
645  {
646  r_p_value = &p_e->m_value;
647  return;
648  }
649  }
650  r_p_value = 0;
651  }
652 
653  void
654  get_start_it_state(pointer& r_p_value, size_type& r_pos)
655  {
656  for (r_pos = 0; r_pos < m_num_e; ++r_pos)
657  {
658  entry_pointer p_e = &m_entries[r_pos];
659  if (p_e->m_stat == valid_entry_status)
660  {
661  r_p_value = &p_e->m_value;
662  return;
663  }
664  }
665  r_p_value = 0;
666  }
667 
668 #ifdef _GLIBCXX_DEBUG
669  void
670  assert_entry_array_valid(const entry_array, false_type,
671  const char*, int) const;
672 
673  void
674  assert_entry_array_valid(const entry_array, true_type,
675  const char*, int) const;
676 #endif
677 
678  static entry_allocator s_entry_allocator;
679  static iterator s_end_it;
680  static const_iterator s_const_end_it;
681 
682  size_type m_num_e;
683  size_type m_num_used_e;
684  entry_pointer m_entries;
685 
686  enum
687  {
688  store_hash_ok = !Store_Hash
689  || !is_same<Hash_Fn, __gnu_pbds::null_type>::value
690  };
691 
692  PB_DS_STATIC_ASSERT(sth, store_hash_ok);
693  };
694 
705 
706 #undef PB_DS_CLASS_T_DEC
707 #undef PB_DS_CLASS_C_DEC
708 #undef PB_DS_HASH_EQ_FN_C_DEC
709 #undef PB_DS_RANGED_PROBE_FN_C_DEC
710 #undef PB_DS_GP_HASH_TRAITS_BASE
711 #undef PB_DS_DEBUG_MAP_BASE_C_DEC
712 #undef PB_DS_GP_HASH_NAME
713  } // namespace detail
714 } // namespace __gnu_pbds