libstdc++
gp_ht_map_.hpp
Go to the documentation of this file.
1// -*- C++ -*-
2
3// Copyright (C) 2005-2021 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
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
55namespace __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 rebind_traits<_Alloc, Key>::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
173 typedef typename entry_traits::allocator_type entry_allocator;
174 typedef typename entry_traits::pointer entry_pointer;
175 typedef typename entry_traits::const_pointer const_entry_pointer;
176 typedef typename entry_traits::reference entry_reference;
177 typedef typename entry_traits::const_reference const_entry_reference;
178 typedef typename entry_traits::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 _GLIBCXX_NODISCARD inline bool
284 empty() const;
285
286 /// Return current hash_fn.
287 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&
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&
305
306 /// Return current const probe_fn.
307 const Probe_Fn&
309
310 /// Return current comb_probe_fn.
311 Comb_Probe_Fn&
313
314 /// Return current const comb_probe_fn.
315 const Comb_Probe_Fn&
317
318 /// Return current resize_policy.
319 Resize_Policy&
321
322 /// Return current const resize_policy.
323 const Resize_Policy&
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
GNU extensions for policy-based data structures for public use.
Struct holding two objects of arbitrary type.
Definition: stl_pair.h:213
Primary template for representation of stored data. Two types of data can be stored: value and hash.
Consistent API for accessing allocator-related types.
Traits for abstract types.
bool empty() const
True if size() == 0.
Comb_Probe_Fn & get_comb_probe_fn()
Return current comb_probe_fn.
const Comb_Probe_Fn & get_comb_probe_fn() const
Return current const comb_probe_fn.
const Hash_Fn & get_hash_fn() const
Return current const hash_fn.
Resize_Policy & get_resize_policy()
Return current resize_policy.
Eq_Fn & get_eq_fn()
Return current eq_fn.
const Eq_Fn & get_eq_fn() const
Return current const eq_fn.
Probe_Fn & get_probe_fn()
Return current probe_fn.
const Resize_Policy & get_resize_policy() const
Return current const resize_policy.
Hash_Fn & get_hash_fn()
Return current hash_fn.
const Probe_Fn & get_probe_fn() const
Return current const probe_fn.