Mercurial > hg > CbC > CbC_gcc
comparison gcc/hash-table.h @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* A type-safe hash table template. | 1 /* A type-safe hash table template. |
2 Copyright (C) 2012-2018 Free Software Foundation, Inc. | 2 Copyright (C) 2012-2020 Free Software Foundation, Inc. |
3 Contributed by Lawrence Crowl <crowl@google.com> | 3 Contributed by Lawrence Crowl <crowl@google.com> |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
33 2. The type used to describe how to handle the value type within | 33 2. The type used to describe how to handle the value type within |
34 the hash table. This descriptor type provides the hash table with | 34 the hash table. This descriptor type provides the hash table with |
35 several things. | 35 several things. |
36 | 36 |
37 - A typedef named 'value_type' to the value type (from above). | 37 - A typedef named 'value_type' to the value type (from above). |
38 Provided a suitable Descriptor class it may be a user-defined, | |
39 non-POD type. | |
38 | 40 |
39 - A static member function named 'hash' that takes a value_type | 41 - A static member function named 'hash' that takes a value_type |
40 (or 'const value_type &') and returns a hashval_t value. | 42 (or 'const value_type &') and returns a hashval_t value. |
41 | 43 |
42 - A typedef named 'compare_type' that is used to test when a value | 44 - A typedef named 'compare_type' that is used to test when a value |
43 is found. This type is the comparison type. Usually, it will be the | 45 is found. This type is the comparison type. Usually, it will be |
44 same as value_type. If it is not the same type, you must generally | 46 the same as value_type and may be a user-defined, non-POD type. |
45 explicitly compute hash values and pass them to the hash table. | 47 If it is not the same type, you must generally explicitly compute |
48 hash values and pass them to the hash table. | |
46 | 49 |
47 - A static member function named 'equal' that takes a value_type | 50 - A static member function named 'equal' that takes a value_type |
48 and a compare_type, and returns a bool. Both arguments can be | 51 and a compare_type, and returns a bool. Both arguments can be |
49 const references. | 52 const references. |
50 | 53 |
165 | 168 |
166 You can then use any of the functions in hash_table's public interface. | 169 You can then use any of the functions in hash_table's public interface. |
167 See hash_table for details. The interface is very similar to libiberty's | 170 See hash_table for details. The interface is very similar to libiberty's |
168 htab_t. | 171 htab_t. |
169 | 172 |
173 If a hash table is used only in some rare cases, it is possible | |
174 to construct the hash_table lazily before first use. This is done | |
175 through: | |
176 | |
177 hash_table <some_type_hasher, true> some_type_hash_table; | |
178 | |
179 which will cause whatever methods actually need the allocated entries | |
180 array to allocate it later. | |
181 | |
170 | 182 |
171 EASY DESCRIPTORS FOR POINTERS | 183 EASY DESCRIPTORS FOR POINTERS |
172 | 184 |
173 There are four descriptors for pointer elements, one for each of | 185 There are four descriptors for pointer elements, one for each of |
174 the removal policies above: | 186 the removal policies above: |
239 #include "mem-stats-traits.h" | 251 #include "mem-stats-traits.h" |
240 #include "hash-traits.h" | 252 #include "hash-traits.h" |
241 #include "hash-map-traits.h" | 253 #include "hash-map-traits.h" |
242 | 254 |
243 template<typename, typename, typename> class hash_map; | 255 template<typename, typename, typename> class hash_map; |
244 template<typename, typename> class hash_set; | 256 template<typename, bool, typename> class hash_set; |
245 | 257 |
246 /* The ordinary memory allocator. */ | 258 /* The ordinary memory allocator. */ |
247 /* FIXME (crowl): This allocator may be extracted for wider sharing later. */ | 259 /* FIXME (crowl): This allocator may be extracted for wider sharing later. */ |
248 | 260 |
249 template <typename Type> | 261 template <typename Type> |
284 hashval_t shift; | 296 hashval_t shift; |
285 }; | 297 }; |
286 | 298 |
287 extern struct prime_ent const prime_tab[]; | 299 extern struct prime_ent const prime_tab[]; |
288 | 300 |
301 /* Limit number of comparisons when calling hash_table<>::verify. */ | |
302 extern unsigned int hash_table_sanitize_eq_limit; | |
289 | 303 |
290 /* Functions for computing hash table indexes. */ | 304 /* Functions for computing hash table indexes. */ |
291 | 305 |
292 extern unsigned int hash_table_higher_prime_index (unsigned long n) | 306 extern unsigned int hash_table_higher_prime_index (unsigned long n) |
293 ATTRIBUTE_PURE; | 307 ATTRIBUTE_PURE; |
308 | |
309 extern ATTRIBUTE_NORETURN ATTRIBUTE_COLD void hashtab_chk_error (); | |
294 | 310 |
295 /* Return X % Y using multiplicative inverse values INV and SHIFT. | 311 /* Return X % Y using multiplicative inverse values INV and SHIFT. |
296 | 312 |
297 The multiplicative inverses computed above are for 32-bit types, | 313 The multiplicative inverses computed above are for 32-bit types, |
298 and requires that we be able to compute a highpart multiply. | 314 and requires that we be able to compute a highpart multiply. |
351 | 367 |
352 Storage is an implementation detail and should not be used outside the | 368 Storage is an implementation detail and should not be used outside the |
353 hash table code. | 369 hash table code. |
354 | 370 |
355 */ | 371 */ |
356 template <typename Descriptor, | 372 template <typename Descriptor, bool Lazy = false, |
357 template<typename Type> class Allocator = xcallocator> | 373 template<typename Type> class Allocator = xcallocator> |
358 class hash_table | 374 class hash_table |
359 { | 375 { |
360 typedef typename Descriptor::value_type value_type; | 376 typedef typename Descriptor::value_type value_type; |
361 typedef typename Descriptor::compare_type compare_type; | 377 typedef typename Descriptor::compare_type compare_type; |
362 | 378 |
363 public: | 379 public: |
364 explicit hash_table (size_t, bool ggc = false, | 380 explicit hash_table (size_t, bool ggc = false, |
381 bool sanitize_eq_and_hash = true, | |
365 bool gather_mem_stats = GATHER_STATISTICS, | 382 bool gather_mem_stats = GATHER_STATISTICS, |
366 mem_alloc_origin origin = HASH_TABLE_ORIGIN | 383 mem_alloc_origin origin = HASH_TABLE_ORIGIN |
367 CXX_MEM_STAT_INFO); | 384 CXX_MEM_STAT_INFO); |
368 explicit hash_table (const hash_table &, bool ggc = false, | 385 explicit hash_table (const hash_table &, bool ggc = false, |
386 bool sanitize_eq_and_hash = true, | |
369 bool gather_mem_stats = GATHER_STATISTICS, | 387 bool gather_mem_stats = GATHER_STATISTICS, |
370 mem_alloc_origin origin = HASH_TABLE_ORIGIN | 388 mem_alloc_origin origin = HASH_TABLE_ORIGIN |
371 CXX_MEM_STAT_INFO); | 389 CXX_MEM_STAT_INFO); |
372 ~hash_table (); | 390 ~hash_table (); |
373 | 391 |
374 /* Create a hash_table in gc memory. */ | 392 /* Create a hash_table in gc memory. */ |
375 static hash_table * | 393 static hash_table * |
376 create_ggc (size_t n CXX_MEM_STAT_INFO) | 394 create_ggc (size_t n, bool sanitize_eq_and_hash = true CXX_MEM_STAT_INFO) |
377 { | 395 { |
378 hash_table *table = ggc_alloc<hash_table> (); | 396 hash_table *table = ggc_alloc<hash_table> (); |
379 new (table) hash_table (n, true, GATHER_STATISTICS, | 397 new (table) hash_table (n, true, sanitize_eq_and_hash, GATHER_STATISTICS, |
380 HASH_TABLE_ORIGIN PASS_MEM_STAT); | 398 HASH_TABLE_ORIGIN PASS_MEM_STAT); |
381 return table; | 399 return table; |
382 } | 400 } |
383 | 401 |
384 /* Current size (in entries) of the hash table. */ | 402 /* Current size (in entries) of the hash table. */ |
390 /* Return the current number of elements in this hash table. */ | 408 /* Return the current number of elements in this hash table. */ |
391 size_t elements_with_deleted () const { return m_n_elements; } | 409 size_t elements_with_deleted () const { return m_n_elements; } |
392 | 410 |
393 /* This function clears all entries in this hash table. */ | 411 /* This function clears all entries in this hash table. */ |
394 void empty () { if (elements ()) empty_slow (); } | 412 void empty () { if (elements ()) empty_slow (); } |
413 | |
414 /* Return true when there are no elements in this hash table. */ | |
415 bool is_empty () const { return elements () == 0; } | |
395 | 416 |
396 /* This function clears a specified SLOT in a hash table. It is | 417 /* This function clears a specified SLOT in a hash table. It is |
397 useful when you've already done the lookup and don't want to do it | 418 useful when you've already done the lookup and don't want to do it |
398 again. */ | 419 again. */ |
399 void clear_slot (value_type *); | 420 void clear_slot (value_type *); |
420 call clear_slot on the slot returned (possibly after doing some | 441 call clear_slot on the slot returned (possibly after doing some |
421 checks). To insert an entry, call this with insert=INSERT, then | 442 checks). To insert an entry, call this with insert=INSERT, then |
422 write the value you want into the returned slot. When inserting an | 443 write the value you want into the returned slot. When inserting an |
423 entry, NULL may be returned if memory allocation fails. */ | 444 entry, NULL may be returned if memory allocation fails. */ |
424 value_type *find_slot_with_hash (const compare_type &comparable, | 445 value_type *find_slot_with_hash (const compare_type &comparable, |
425 hashval_t hash, enum insert_option insert); | 446 hashval_t hash, enum insert_option insert); |
426 | 447 |
427 /* This function deletes an element with the given COMPARABLE value | 448 /* This function deletes an element with the given COMPARABLE value |
428 from hash table starting with the given HASH. If there is no | 449 from hash table starting with the given HASH. If there is no |
429 matching element in the hash table, this function does nothing. */ | 450 matching element in the hash table, this function does nothing. */ |
430 void remove_elt_with_hash (const compare_type &, hashval_t); | 451 void remove_elt_with_hash (const compare_type &, hashval_t); |
470 value_type *m_limit; | 491 value_type *m_limit; |
471 }; | 492 }; |
472 | 493 |
473 iterator begin () const | 494 iterator begin () const |
474 { | 495 { |
496 if (Lazy && m_entries == NULL) | |
497 return iterator (); | |
475 iterator iter (m_entries, m_entries + m_size); | 498 iterator iter (m_entries, m_entries + m_size); |
476 iter.slide (); | 499 iter.slide (); |
477 return iter; | 500 return iter; |
478 } | 501 } |
479 | 502 |
483 { | 506 { |
484 return m_searches ? static_cast <double> (m_collisions) / m_searches : 0; | 507 return m_searches ? static_cast <double> (m_collisions) / m_searches : 0; |
485 } | 508 } |
486 | 509 |
487 private: | 510 private: |
511 /* FIXME: Make the class assignable. See pr90959. */ | |
512 void operator= (hash_table&); | |
513 | |
488 template<typename T> friend void gt_ggc_mx (hash_table<T> *); | 514 template<typename T> friend void gt_ggc_mx (hash_table<T> *); |
489 template<typename T> friend void gt_pch_nx (hash_table<T> *); | 515 template<typename T> friend void gt_pch_nx (hash_table<T> *); |
490 template<typename T> friend void | 516 template<typename T> friend void |
491 hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *); | 517 hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *); |
492 template<typename T, typename U, typename V> friend void | 518 template<typename T, typename U, typename V> friend void |
493 gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *); | 519 gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *); |
494 template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *, | 520 template<typename T, typename U> |
495 gt_pointer_operator, | 521 friend void gt_pch_nx (hash_set<T, false, U> *, gt_pointer_operator, void *); |
496 void *); | |
497 template<typename T> friend void gt_pch_nx (hash_table<T> *, | 522 template<typename T> friend void gt_pch_nx (hash_table<T> *, |
498 gt_pointer_operator, void *); | 523 gt_pointer_operator, void *); |
499 | 524 |
500 template<typename T> friend void gt_cleare_cache (hash_table<T> *); | 525 template<typename T> friend void gt_cleare_cache (hash_table<T> *); |
501 | 526 |
502 void empty_slow (); | 527 void empty_slow (); |
503 | 528 |
504 value_type *alloc_entries (size_t n CXX_MEM_STAT_INFO) const; | 529 value_type *alloc_entries (size_t n CXX_MEM_STAT_INFO) const; |
505 value_type *find_empty_slot_for_expand (hashval_t); | 530 value_type *find_empty_slot_for_expand (hashval_t); |
531 void verify (const compare_type &comparable, hashval_t hash); | |
506 bool too_empty_p (unsigned int); | 532 bool too_empty_p (unsigned int); |
507 void expand (); | 533 void expand (); |
508 static bool is_deleted (value_type &v) | 534 static bool is_deleted (value_type &v) |
509 { | 535 { |
510 return Descriptor::is_deleted (v); | 536 return Descriptor::is_deleted (v); |
549 unsigned int m_size_prime_index; | 575 unsigned int m_size_prime_index; |
550 | 576 |
551 /* if m_entries is stored in ggc memory. */ | 577 /* if m_entries is stored in ggc memory. */ |
552 bool m_ggc; | 578 bool m_ggc; |
553 | 579 |
580 /* True if the table should be sanitized for equal and hash functions. */ | |
581 bool m_sanitize_eq_and_hash; | |
582 | |
554 /* If we should gather memory statistics for the table. */ | 583 /* If we should gather memory statistics for the table. */ |
584 #if GATHER_STATISTICS | |
555 bool m_gather_mem_stats; | 585 bool m_gather_mem_stats; |
586 #else | |
587 static const bool m_gather_mem_stats = false; | |
588 #endif | |
556 }; | 589 }; |
557 | 590 |
558 /* As mem-stats.h heavily utilizes hash maps (hash tables), we have to include | 591 /* As mem-stats.h heavily utilizes hash maps (hash tables), we have to include |
559 mem-stats.h after hash_table declaration. */ | 592 mem-stats.h after hash_table declaration. */ |
560 | 593 |
564 extern mem_alloc_description<mem_usage>& hash_table_usage (void); | 597 extern mem_alloc_description<mem_usage>& hash_table_usage (void); |
565 | 598 |
566 /* Support function for statistics. */ | 599 /* Support function for statistics. */ |
567 extern void dump_hash_table_loc_statistics (void); | 600 extern void dump_hash_table_loc_statistics (void); |
568 | 601 |
569 template<typename Descriptor, template<typename Type> class Allocator> | 602 template<typename Descriptor, bool Lazy, |
570 hash_table<Descriptor, Allocator>::hash_table (size_t size, bool ggc, bool | 603 template<typename Type> class Allocator> |
571 gather_mem_stats, | 604 hash_table<Descriptor, Lazy, Allocator>::hash_table (size_t size, bool ggc, |
572 mem_alloc_origin origin | 605 bool sanitize_eq_and_hash, |
573 MEM_STAT_DECL) : | 606 bool gather_mem_stats |
607 ATTRIBUTE_UNUSED, | |
608 mem_alloc_origin origin | |
609 MEM_STAT_DECL) : | |
574 m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0), | 610 m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0), |
575 m_ggc (ggc), m_gather_mem_stats (gather_mem_stats) | 611 m_ggc (ggc), m_sanitize_eq_and_hash (sanitize_eq_and_hash) |
612 #if GATHER_STATISTICS | |
613 , m_gather_mem_stats (gather_mem_stats) | |
614 #endif | |
576 { | 615 { |
577 unsigned int size_prime_index; | 616 unsigned int size_prime_index; |
578 | 617 |
579 size_prime_index = hash_table_higher_prime_index (size); | 618 size_prime_index = hash_table_higher_prime_index (size); |
580 size = prime_tab[size_prime_index].prime; | 619 size = prime_tab[size_prime_index].prime; |
620 | |
621 if (m_gather_mem_stats) | |
622 hash_table_usage ().register_descriptor (this, origin, ggc | |
623 FINAL_PASS_MEM_STAT); | |
624 | |
625 if (Lazy) | |
626 m_entries = NULL; | |
627 else | |
628 m_entries = alloc_entries (size PASS_MEM_STAT); | |
629 m_size = size; | |
630 m_size_prime_index = size_prime_index; | |
631 } | |
632 | |
633 template<typename Descriptor, bool Lazy, | |
634 template<typename Type> class Allocator> | |
635 hash_table<Descriptor, Lazy, Allocator>::hash_table (const hash_table &h, | |
636 bool ggc, | |
637 bool sanitize_eq_and_hash, | |
638 bool gather_mem_stats | |
639 ATTRIBUTE_UNUSED, | |
640 mem_alloc_origin origin | |
641 MEM_STAT_DECL) : | |
642 m_n_elements (h.m_n_elements), m_n_deleted (h.m_n_deleted), | |
643 m_searches (0), m_collisions (0), m_ggc (ggc), | |
644 m_sanitize_eq_and_hash (sanitize_eq_and_hash) | |
645 #if GATHER_STATISTICS | |
646 , m_gather_mem_stats (gather_mem_stats) | |
647 #endif | |
648 { | |
649 size_t size = h.m_size; | |
581 | 650 |
582 if (m_gather_mem_stats) | 651 if (m_gather_mem_stats) |
583 hash_table_usage ().register_descriptor (this, origin, ggc | 652 hash_table_usage ().register_descriptor (this, origin, ggc |
584 FINAL_PASS_MEM_STAT); | 653 FINAL_PASS_MEM_STAT); |
585 | 654 |
586 m_entries = alloc_entries (size PASS_MEM_STAT); | 655 if (Lazy && h.m_entries == NULL) |
587 m_size = size; | 656 m_entries = NULL; |
588 m_size_prime_index = size_prime_index; | 657 else |
589 } | 658 { |
590 | 659 value_type *nentries = alloc_entries (size PASS_MEM_STAT); |
591 template<typename Descriptor, template<typename Type> class Allocator> | 660 for (size_t i = 0; i < size; ++i) |
592 hash_table<Descriptor, Allocator>::hash_table (const hash_table &h, bool ggc, | 661 { |
593 bool gather_mem_stats, | 662 value_type &entry = h.m_entries[i]; |
594 mem_alloc_origin origin | 663 if (is_deleted (entry)) |
595 MEM_STAT_DECL) : | 664 mark_deleted (nentries[i]); |
596 m_n_elements (h.m_n_elements), m_n_deleted (h.m_n_deleted), | 665 else if (!is_empty (entry)) |
597 m_searches (0), m_collisions (0), m_ggc (ggc), | 666 new ((void*) (nentries + i)) value_type (entry); |
598 m_gather_mem_stats (gather_mem_stats) | 667 } |
599 { | 668 m_entries = nentries; |
600 size_t size = h.m_size; | 669 } |
601 | |
602 if (m_gather_mem_stats) | |
603 hash_table_usage ().register_descriptor (this, origin, ggc | |
604 FINAL_PASS_MEM_STAT); | |
605 | |
606 value_type *nentries = alloc_entries (size PASS_MEM_STAT); | |
607 for (size_t i = 0; i < size; ++i) | |
608 { | |
609 value_type &entry = h.m_entries[i]; | |
610 if (is_deleted (entry)) | |
611 mark_deleted (nentries[i]); | |
612 else if (!is_empty (entry)) | |
613 nentries[i] = entry; | |
614 } | |
615 m_entries = nentries; | |
616 m_size = size; | 670 m_size = size; |
617 m_size_prime_index = h.m_size_prime_index; | 671 m_size_prime_index = h.m_size_prime_index; |
618 } | 672 } |
619 | 673 |
620 template<typename Descriptor, template<typename Type> class Allocator> | 674 template<typename Descriptor, bool Lazy, |
621 hash_table<Descriptor, Allocator>::~hash_table () | 675 template<typename Type> class Allocator> |
622 { | 676 hash_table<Descriptor, Lazy, Allocator>::~hash_table () |
623 for (size_t i = m_size - 1; i < m_size; i--) | 677 { |
624 if (!is_empty (m_entries[i]) && !is_deleted (m_entries[i])) | 678 if (!Lazy || m_entries) |
625 Descriptor::remove (m_entries[i]); | 679 { |
626 | 680 for (size_t i = m_size - 1; i < m_size; i--) |
627 if (!m_ggc) | 681 if (!is_empty (m_entries[i]) && !is_deleted (m_entries[i])) |
628 Allocator <value_type> ::data_free (m_entries); | 682 Descriptor::remove (m_entries[i]); |
629 else | 683 |
630 ggc_free (m_entries); | 684 if (!m_ggc) |
631 | 685 Allocator <value_type> ::data_free (m_entries); |
632 if (m_gather_mem_stats) | 686 else |
633 hash_table_usage ().release_instance_overhead (this, | 687 ggc_free (m_entries); |
634 sizeof (value_type) * m_size, | 688 if (m_gather_mem_stats) |
635 true); | 689 hash_table_usage ().release_instance_overhead (this, |
690 sizeof (value_type) | |
691 * m_size, true); | |
692 } | |
693 else if (m_gather_mem_stats) | |
694 hash_table_usage ().unregister_descriptor (this); | |
636 } | 695 } |
637 | 696 |
638 /* This function returns an array of empty hash table elements. */ | 697 /* This function returns an array of empty hash table elements. */ |
639 | 698 |
640 template<typename Descriptor, template<typename Type> class Allocator> | 699 template<typename Descriptor, bool Lazy, |
641 inline typename hash_table<Descriptor, Allocator>::value_type * | 700 template<typename Type> class Allocator> |
642 hash_table<Descriptor, Allocator>::alloc_entries (size_t n MEM_STAT_DECL) const | 701 inline typename hash_table<Descriptor, Lazy, Allocator>::value_type * |
702 hash_table<Descriptor, Lazy, | |
703 Allocator>::alloc_entries (size_t n MEM_STAT_DECL) const | |
643 { | 704 { |
644 value_type *nentries; | 705 value_type *nentries; |
645 | 706 |
646 if (m_gather_mem_stats) | 707 if (m_gather_mem_stats) |
647 hash_table_usage ().register_instance_overhead (sizeof (value_type) * n, this); | 708 hash_table_usage ().register_instance_overhead (sizeof (value_type) * n, this); |
650 nentries = Allocator <value_type> ::data_alloc (n); | 711 nentries = Allocator <value_type> ::data_alloc (n); |
651 else | 712 else |
652 nentries = ::ggc_cleared_vec_alloc<value_type> (n PASS_MEM_STAT); | 713 nentries = ::ggc_cleared_vec_alloc<value_type> (n PASS_MEM_STAT); |
653 | 714 |
654 gcc_assert (nentries != NULL); | 715 gcc_assert (nentries != NULL); |
655 for (size_t i = 0; i < n; i++) | 716 if (!Descriptor::empty_zero_p) |
656 mark_empty (nentries[i]); | 717 for (size_t i = 0; i < n; i++) |
718 mark_empty (nentries[i]); | |
657 | 719 |
658 return nentries; | 720 return nentries; |
659 } | 721 } |
660 | 722 |
661 /* Similar to find_slot, but without several unwanted side effects: | 723 /* Similar to find_slot, but without several unwanted side effects: |
663 - Does not change the count of elements/searches/collisions in the | 725 - Does not change the count of elements/searches/collisions in the |
664 hash table. | 726 hash table. |
665 This function also assumes there are no deleted entries in the table. | 727 This function also assumes there are no deleted entries in the table. |
666 HASH is the hash value for the element to be inserted. */ | 728 HASH is the hash value for the element to be inserted. */ |
667 | 729 |
668 template<typename Descriptor, template<typename Type> class Allocator> | 730 template<typename Descriptor, bool Lazy, |
669 typename hash_table<Descriptor, Allocator>::value_type * | 731 template<typename Type> class Allocator> |
670 hash_table<Descriptor, Allocator>::find_empty_slot_for_expand (hashval_t hash) | 732 typename hash_table<Descriptor, Lazy, Allocator>::value_type * |
733 hash_table<Descriptor, Lazy, | |
734 Allocator>::find_empty_slot_for_expand (hashval_t hash) | |
671 { | 735 { |
672 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); | 736 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); |
673 size_t size = m_size; | 737 size_t size = m_size; |
674 value_type *slot = m_entries + index; | 738 value_type *slot = m_entries + index; |
675 hashval_t hash2; | 739 hashval_t hash2; |
692 } | 756 } |
693 } | 757 } |
694 | 758 |
695 /* Return true if the current table is excessively big for ELTS elements. */ | 759 /* Return true if the current table is excessively big for ELTS elements. */ |
696 | 760 |
697 template<typename Descriptor, template<typename Type> class Allocator> | 761 template<typename Descriptor, bool Lazy, |
762 template<typename Type> class Allocator> | |
698 inline bool | 763 inline bool |
699 hash_table<Descriptor, Allocator>::too_empty_p (unsigned int elts) | 764 hash_table<Descriptor, Lazy, Allocator>::too_empty_p (unsigned int elts) |
700 { | 765 { |
701 return elts * 8 < m_size && m_size > 32; | 766 return elts * 8 < m_size && m_size > 32; |
702 } | 767 } |
703 | 768 |
704 /* The following function changes size of memory allocated for the | 769 /* The following function changes size of memory allocated for the |
706 of the table after the call will be about 50%. Naturally the hash | 771 of the table after the call will be about 50%. Naturally the hash |
707 table must already exist. Remember also that the place of the | 772 table must already exist. Remember also that the place of the |
708 table entries is changed. If memory allocation fails, this function | 773 table entries is changed. If memory allocation fails, this function |
709 will abort. */ | 774 will abort. */ |
710 | 775 |
711 template<typename Descriptor, template<typename Type> class Allocator> | 776 template<typename Descriptor, bool Lazy, |
777 template<typename Type> class Allocator> | |
712 void | 778 void |
713 hash_table<Descriptor, Allocator>::expand () | 779 hash_table<Descriptor, Lazy, Allocator>::expand () |
714 { | 780 { |
715 value_type *oentries = m_entries; | 781 value_type *oentries = m_entries; |
716 unsigned int oindex = m_size_prime_index; | 782 unsigned int oindex = m_size_prime_index; |
717 size_t osize = size (); | 783 size_t osize = size (); |
718 value_type *olimit = oentries + osize; | 784 value_type *olimit = oentries + osize; |
751 value_type &x = *p; | 817 value_type &x = *p; |
752 | 818 |
753 if (!is_empty (x) && !is_deleted (x)) | 819 if (!is_empty (x) && !is_deleted (x)) |
754 { | 820 { |
755 value_type *q = find_empty_slot_for_expand (Descriptor::hash (x)); | 821 value_type *q = find_empty_slot_for_expand (Descriptor::hash (x)); |
756 | 822 new ((void*) q) value_type (x); |
757 *q = x; | |
758 } | 823 } |
759 | 824 |
760 p++; | 825 p++; |
761 } | 826 } |
762 while (p < olimit); | 827 while (p < olimit); |
767 ggc_free (oentries); | 832 ggc_free (oentries); |
768 } | 833 } |
769 | 834 |
770 /* Implements empty() in cases where it isn't a no-op. */ | 835 /* Implements empty() in cases where it isn't a no-op. */ |
771 | 836 |
772 template<typename Descriptor, template<typename Type> class Allocator> | 837 template<typename Descriptor, bool Lazy, |
838 template<typename Type> class Allocator> | |
773 void | 839 void |
774 hash_table<Descriptor, Allocator>::empty_slow () | 840 hash_table<Descriptor, Lazy, Allocator>::empty_slow () |
775 { | 841 { |
776 size_t size = m_size; | 842 size_t size = m_size; |
777 size_t nsize = size; | 843 size_t nsize = size; |
778 value_type *entries = m_entries; | 844 value_type *entries = m_entries; |
779 int i; | 845 |
780 | 846 for (size_t i = size - 1; i < size; i--) |
781 for (i = size - 1; i >= 0; i--) | |
782 if (!is_empty (entries[i]) && !is_deleted (entries[i])) | 847 if (!is_empty (entries[i]) && !is_deleted (entries[i])) |
783 Descriptor::remove (entries[i]); | 848 Descriptor::remove (entries[i]); |
784 | 849 |
785 /* Instead of clearing megabyte, downsize the table. */ | 850 /* Instead of clearing megabyte, downsize the table. */ |
786 if (size > 1024*1024 / sizeof (value_type)) | 851 if (size > 1024*1024 / sizeof (value_type)) |
788 else if (too_empty_p (m_n_elements)) | 853 else if (too_empty_p (m_n_elements)) |
789 nsize = m_n_elements * 2; | 854 nsize = m_n_elements * 2; |
790 | 855 |
791 if (nsize != size) | 856 if (nsize != size) |
792 { | 857 { |
793 int nindex = hash_table_higher_prime_index (nsize); | 858 unsigned int nindex = hash_table_higher_prime_index (nsize); |
794 int nsize = prime_tab[nindex].prime; | 859 |
860 nsize = prime_tab[nindex].prime; | |
795 | 861 |
796 if (!m_ggc) | 862 if (!m_ggc) |
797 Allocator <value_type> ::data_free (m_entries); | 863 Allocator <value_type> ::data_free (m_entries); |
798 else | 864 else |
799 ggc_free (m_entries); | 865 ggc_free (m_entries); |
800 | 866 |
801 m_entries = alloc_entries (nsize); | 867 m_entries = alloc_entries (nsize); |
802 m_size = nsize; | 868 m_size = nsize; |
803 m_size_prime_index = nindex; | 869 m_size_prime_index = nindex; |
804 } | 870 } |
871 else if (Descriptor::empty_zero_p) | |
872 memset ((void *) entries, 0, size * sizeof (value_type)); | |
805 else | 873 else |
806 { | 874 for (size_t i = 0; i < size; i++) |
807 #ifndef BROKEN_VALUE_INITIALIZATION | 875 mark_empty (entries[i]); |
808 for ( ; size; ++entries, --size) | 876 |
809 *entries = value_type (); | |
810 #else | |
811 memset (entries, 0, size * sizeof (value_type)); | |
812 #endif | |
813 } | |
814 m_n_deleted = 0; | 877 m_n_deleted = 0; |
815 m_n_elements = 0; | 878 m_n_elements = 0; |
816 } | 879 } |
817 | 880 |
818 /* This function clears a specified SLOT in a hash table. It is | 881 /* This function clears a specified SLOT in a hash table. It is |
819 useful when you've already done the lookup and don't want to do it | 882 useful when you've already done the lookup and don't want to do it |
820 again. */ | 883 again. */ |
821 | 884 |
822 template<typename Descriptor, template<typename Type> class Allocator> | 885 template<typename Descriptor, bool Lazy, |
886 template<typename Type> class Allocator> | |
823 void | 887 void |
824 hash_table<Descriptor, Allocator>::clear_slot (value_type *slot) | 888 hash_table<Descriptor, Lazy, Allocator>::clear_slot (value_type *slot) |
825 { | 889 { |
826 gcc_checking_assert (!(slot < m_entries || slot >= m_entries + size () | 890 gcc_checking_assert (!(slot < m_entries || slot >= m_entries + size () |
827 || is_empty (*slot) || is_deleted (*slot))); | 891 || is_empty (*slot) || is_deleted (*slot))); |
828 | 892 |
829 Descriptor::remove (*slot); | 893 Descriptor::remove (*slot); |
834 | 898 |
835 /* This function searches for a hash table entry equal to the given | 899 /* This function searches for a hash table entry equal to the given |
836 COMPARABLE element starting with the given HASH value. It cannot | 900 COMPARABLE element starting with the given HASH value. It cannot |
837 be used to insert or delete an element. */ | 901 be used to insert or delete an element. */ |
838 | 902 |
839 template<typename Descriptor, template<typename Type> class Allocator> | 903 template<typename Descriptor, bool Lazy, |
840 typename hash_table<Descriptor, Allocator>::value_type & | 904 template<typename Type> class Allocator> |
841 hash_table<Descriptor, Allocator> | 905 typename hash_table<Descriptor, Lazy, Allocator>::value_type & |
906 hash_table<Descriptor, Lazy, Allocator> | |
842 ::find_with_hash (const compare_type &comparable, hashval_t hash) | 907 ::find_with_hash (const compare_type &comparable, hashval_t hash) |
843 { | 908 { |
844 m_searches++; | 909 m_searches++; |
845 size_t size = m_size; | 910 size_t size = m_size; |
846 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); | 911 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); |
847 | 912 |
913 if (Lazy && m_entries == NULL) | |
914 m_entries = alloc_entries (size); | |
848 value_type *entry = &m_entries[index]; | 915 value_type *entry = &m_entries[index]; |
849 if (is_empty (*entry) | 916 if (is_empty (*entry) |
850 || (!is_deleted (*entry) && Descriptor::equal (*entry, comparable))) | 917 || (!is_deleted (*entry) && Descriptor::equal (*entry, comparable))) |
851 return *entry; | 918 return *entry; |
852 | 919 |
859 index -= size; | 926 index -= size; |
860 | 927 |
861 entry = &m_entries[index]; | 928 entry = &m_entries[index]; |
862 if (is_empty (*entry) | 929 if (is_empty (*entry) |
863 || (!is_deleted (*entry) && Descriptor::equal (*entry, comparable))) | 930 || (!is_deleted (*entry) && Descriptor::equal (*entry, comparable))) |
864 return *entry; | 931 { |
932 #if CHECKING_P | |
933 if (m_sanitize_eq_and_hash) | |
934 verify (comparable, hash); | |
935 #endif | |
936 return *entry; | |
937 } | |
865 } | 938 } |
866 } | 939 } |
867 | 940 |
868 /* This function searches for a hash table slot containing an entry | 941 /* This function searches for a hash table slot containing an entry |
869 equal to the given COMPARABLE element and starting with the given | 942 equal to the given COMPARABLE element and starting with the given |
871 call clear_slot on the slot returned (possibly after doing some | 944 call clear_slot on the slot returned (possibly after doing some |
872 checks). To insert an entry, call this with insert=INSERT, then | 945 checks). To insert an entry, call this with insert=INSERT, then |
873 write the value you want into the returned slot. When inserting an | 946 write the value you want into the returned slot. When inserting an |
874 entry, NULL may be returned if memory allocation fails. */ | 947 entry, NULL may be returned if memory allocation fails. */ |
875 | 948 |
876 template<typename Descriptor, template<typename Type> class Allocator> | 949 template<typename Descriptor, bool Lazy, |
877 typename hash_table<Descriptor, Allocator>::value_type * | 950 template<typename Type> class Allocator> |
878 hash_table<Descriptor, Allocator> | 951 typename hash_table<Descriptor, Lazy, Allocator>::value_type * |
952 hash_table<Descriptor, Lazy, Allocator> | |
879 ::find_slot_with_hash (const compare_type &comparable, hashval_t hash, | 953 ::find_slot_with_hash (const compare_type &comparable, hashval_t hash, |
880 enum insert_option insert) | 954 enum insert_option insert) |
881 { | 955 { |
956 if (Lazy && m_entries == NULL) | |
957 { | |
958 if (insert == INSERT) | |
959 m_entries = alloc_entries (m_size); | |
960 else | |
961 return NULL; | |
962 } | |
882 if (insert == INSERT && m_size * 3 <= m_n_elements * 4) | 963 if (insert == INSERT && m_size * 3 <= m_n_elements * 4) |
883 expand (); | 964 expand (); |
884 | 965 |
966 #if CHECKING_P | |
967 if (m_sanitize_eq_and_hash) | |
968 verify (comparable, hash); | |
969 #endif | |
970 | |
885 m_searches++; | 971 m_searches++; |
886 | |
887 value_type *first_deleted_slot = NULL; | 972 value_type *first_deleted_slot = NULL; |
888 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); | 973 hashval_t index = hash_table_mod1 (hash, m_size_prime_index); |
889 hashval_t hash2 = hash_table_mod2 (hash, m_size_prime_index); | 974 hashval_t hash2 = hash_table_mod2 (hash, m_size_prime_index); |
890 value_type *entry = &m_entries[index]; | 975 value_type *entry = &m_entries[index]; |
891 size_t size = m_size; | 976 size_t size = m_size; |
928 | 1013 |
929 m_n_elements++; | 1014 m_n_elements++; |
930 return &m_entries[index]; | 1015 return &m_entries[index]; |
931 } | 1016 } |
932 | 1017 |
1018 /* Verify that all existing elements in th hash table which are | |
1019 equal to COMPARABLE have an equal HASH value provided as argument. */ | |
1020 | |
1021 template<typename Descriptor, bool Lazy, | |
1022 template<typename Type> class Allocator> | |
1023 void | |
1024 hash_table<Descriptor, Lazy, Allocator> | |
1025 ::verify (const compare_type &comparable, hashval_t hash) | |
1026 { | |
1027 for (size_t i = 0; i < MIN (hash_table_sanitize_eq_limit, m_size); i++) | |
1028 { | |
1029 value_type *entry = &m_entries[i]; | |
1030 if (!is_empty (*entry) && !is_deleted (*entry) | |
1031 && hash != Descriptor::hash (*entry) | |
1032 && Descriptor::equal (*entry, comparable)) | |
1033 hashtab_chk_error (); | |
1034 } | |
1035 } | |
1036 | |
933 /* This function deletes an element with the given COMPARABLE value | 1037 /* This function deletes an element with the given COMPARABLE value |
934 from hash table starting with the given HASH. If there is no | 1038 from hash table starting with the given HASH. If there is no |
935 matching element in the hash table, this function does nothing. */ | 1039 matching element in the hash table, this function does nothing. */ |
936 | 1040 |
937 template<typename Descriptor, template<typename Type> class Allocator> | 1041 template<typename Descriptor, bool Lazy, |
1042 template<typename Type> class Allocator> | |
938 void | 1043 void |
939 hash_table<Descriptor, Allocator> | 1044 hash_table<Descriptor, Lazy, Allocator> |
940 ::remove_elt_with_hash (const compare_type &comparable, hashval_t hash) | 1045 ::remove_elt_with_hash (const compare_type &comparable, hashval_t hash) |
941 { | 1046 { |
942 value_type *slot = find_slot_with_hash (comparable, hash, NO_INSERT); | 1047 value_type *slot = find_slot_with_hash (comparable, hash, NO_INSERT); |
943 if (is_empty (*slot)) | 1048 if (slot == NULL) |
944 return; | 1049 return; |
945 | 1050 |
946 Descriptor::remove (*slot); | 1051 Descriptor::remove (*slot); |
947 | 1052 |
948 mark_deleted (*slot); | 1053 mark_deleted (*slot); |
951 | 1056 |
952 /* This function scans over the entire hash table calling CALLBACK for | 1057 /* This function scans over the entire hash table calling CALLBACK for |
953 each live entry. If CALLBACK returns false, the iteration stops. | 1058 each live entry. If CALLBACK returns false, the iteration stops. |
954 ARGUMENT is passed as CALLBACK's second argument. */ | 1059 ARGUMENT is passed as CALLBACK's second argument. */ |
955 | 1060 |
956 template<typename Descriptor, | 1061 template<typename Descriptor, bool Lazy, |
957 template<typename Type> class Allocator> | 1062 template<typename Type> class Allocator> |
958 template<typename Argument, | 1063 template<typename Argument, |
959 int (*Callback) | 1064 int (*Callback) |
960 (typename hash_table<Descriptor, Allocator>::value_type *slot, | 1065 (typename hash_table<Descriptor, Lazy, Allocator>::value_type *slot, |
961 Argument argument)> | 1066 Argument argument)> |
962 void | 1067 void |
963 hash_table<Descriptor, Allocator>::traverse_noresize (Argument argument) | 1068 hash_table<Descriptor, Lazy, Allocator>::traverse_noresize (Argument argument) |
964 { | 1069 { |
1070 if (Lazy && m_entries == NULL) | |
1071 return; | |
1072 | |
965 value_type *slot = m_entries; | 1073 value_type *slot = m_entries; |
966 value_type *limit = slot + size (); | 1074 value_type *limit = slot + size (); |
967 | 1075 |
968 do | 1076 do |
969 { | 1077 { |
977 } | 1085 } |
978 | 1086 |
979 /* Like traverse_noresize, but does resize the table when it is too empty | 1087 /* Like traverse_noresize, but does resize the table when it is too empty |
980 to improve effectivity of subsequent calls. */ | 1088 to improve effectivity of subsequent calls. */ |
981 | 1089 |
982 template <typename Descriptor, | 1090 template <typename Descriptor, bool Lazy, |
983 template <typename Type> class Allocator> | 1091 template <typename Type> class Allocator> |
984 template <typename Argument, | 1092 template <typename Argument, |
985 int (*Callback) | 1093 int (*Callback) |
986 (typename hash_table<Descriptor, Allocator>::value_type *slot, | 1094 (typename hash_table<Descriptor, Lazy, Allocator>::value_type *slot, |
987 Argument argument)> | 1095 Argument argument)> |
988 void | 1096 void |
989 hash_table<Descriptor, Allocator>::traverse (Argument argument) | 1097 hash_table<Descriptor, Lazy, Allocator>::traverse (Argument argument) |
990 { | 1098 { |
991 if (too_empty_p (elements ())) | 1099 if (too_empty_p (elements ()) && (!Lazy || m_entries)) |
992 expand (); | 1100 expand (); |
993 | 1101 |
994 traverse_noresize <Argument, Callback> (argument); | 1102 traverse_noresize <Argument, Callback> (argument); |
995 } | 1103 } |
996 | 1104 |
997 /* Slide down the iterator slots until an active entry is found. */ | 1105 /* Slide down the iterator slots until an active entry is found. */ |
998 | 1106 |
999 template<typename Descriptor, template<typename Type> class Allocator> | 1107 template<typename Descriptor, bool Lazy, |
1108 template<typename Type> class Allocator> | |
1000 void | 1109 void |
1001 hash_table<Descriptor, Allocator>::iterator::slide () | 1110 hash_table<Descriptor, Lazy, Allocator>::iterator::slide () |
1002 { | 1111 { |
1003 for ( ; m_slot < m_limit; ++m_slot ) | 1112 for ( ; m_slot < m_limit; ++m_slot ) |
1004 { | 1113 { |
1005 value_type &x = *m_slot; | 1114 value_type &x = *m_slot; |
1006 if (!is_empty (x) && !is_deleted (x)) | 1115 if (!is_empty (x) && !is_deleted (x)) |
1010 m_limit = NULL; | 1119 m_limit = NULL; |
1011 } | 1120 } |
1012 | 1121 |
1013 /* Bump the iterator. */ | 1122 /* Bump the iterator. */ |
1014 | 1123 |
1015 template<typename Descriptor, template<typename Type> class Allocator> | 1124 template<typename Descriptor, bool Lazy, |
1016 inline typename hash_table<Descriptor, Allocator>::iterator & | 1125 template<typename Type> class Allocator> |
1017 hash_table<Descriptor, Allocator>::iterator::operator ++ () | 1126 inline typename hash_table<Descriptor, Lazy, Allocator>::iterator & |
1127 hash_table<Descriptor, Lazy, Allocator>::iterator::operator ++ () | |
1018 { | 1128 { |
1019 ++m_slot; | 1129 ++m_slot; |
1020 slide (); | 1130 slide (); |
1021 return *this; | 1131 return *this; |
1022 } | 1132 } |