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