|
45 | 45 | #include <limits> |
46 | 46 | #include <new> // __launder |
47 | 47 |
|
| 48 | +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY |
| 49 | +# include <__debug_utils/randomize_range.h> |
| 50 | +# include <__numeric/iota.h> |
| 51 | +#endif |
| 52 | + |
48 | 53 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
49 | 54 | # pragma GCC system_header |
50 | 55 | #endif |
@@ -980,6 +985,9 @@ private: |
980 | 985 | template <bool _UniqueKeys> |
981 | 986 | _LIBCPP_HIDE_FROM_ABI void __do_rehash(size_type __n); |
982 | 987 |
|
| 988 | + template <bool _UniqueKeys> |
| 989 | + _LIBCPP_HIDE_FROM_ABI void __debug_randomize_order(); |
| 990 | + |
983 | 991 | template <class... _Args> |
984 | 992 | _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args); |
985 | 993 |
|
@@ -1702,6 +1710,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __n) _LIBCPP_D |
1702 | 1710 | template <class _Tp, class _Hash, class _Equal, class _Alloc> |
1703 | 1711 | template <bool _UniqueKeys> |
1704 | 1712 | void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) { |
| 1713 | + __debug_randomize_order<_UniqueKeys>(); |
1705 | 1714 | __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc(); |
1706 | 1715 | __bucket_list_.reset(__nbc > 0 ? __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr); |
1707 | 1716 | __bucket_list_.get_deleter().size() = __nbc; |
@@ -1741,6 +1750,54 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) { |
1741 | 1750 | } |
1742 | 1751 | } |
1743 | 1752 |
|
| 1753 | +template <class _Tp, class _Hash, class _Equal, class _Alloc> |
| 1754 | +template <bool _UniqueKeys> |
| 1755 | +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__debug_randomize_order() { |
| 1756 | +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY |
| 1757 | + size_type __total_nodes = size(); |
| 1758 | + size_type __initialized_nodes = 0; |
| 1759 | + |
| 1760 | + // Storage to handle non-assignable, non-default constructible __node_holder. |
| 1761 | + union __nh_storage { |
| 1762 | + __nh_storage() {} |
| 1763 | + ~__nh_storage() {} |
| 1764 | + __node_holder __nh; |
| 1765 | + }; |
| 1766 | + |
| 1767 | + auto __nh_storage_deleter = [&__initialized_nodes](__nh_storage* __p) { |
| 1768 | + for (size_type __i = 0; __i < __initialized_nodes; ++__i) |
| 1769 | + __p[__i].__nh.~__node_holder(); |
| 1770 | + delete[] __p; |
| 1771 | + }; |
| 1772 | + |
| 1773 | + // Allocate storage for nodes and indices. |
| 1774 | + unique_ptr<__nh_storage[], decltype(__nh_storage_deleter)> __nodes( |
| 1775 | + new __nh_storage[__total_nodes], __nh_storage_deleter); |
| 1776 | + unique_ptr<size_type[]> __randomized_indices(new size_type[__total_nodes]); |
| 1777 | + |
| 1778 | + // Move nodes into temporary storage. |
| 1779 | + for (; __initialized_nodes < __total_nodes; ++__initialized_nodes) |
| 1780 | + new (std::addressof(__nodes[__initialized_nodes].__nh)) __node_holder(remove(begin())); |
| 1781 | + |
| 1782 | + // Randomize the order of indices. |
| 1783 | + std::iota(__randomized_indices.get(), __randomized_indices.get() + __total_nodes, size_type{0}); |
| 1784 | + __debug_randomize_range<_ClassicAlgPolicy>(__randomized_indices.get(), __randomized_indices.get() + __total_nodes); |
| 1785 | + |
| 1786 | + // Reinsert nodes into the hash table in randomized order. |
| 1787 | + for (size_type __i = 0; __i < __total_nodes; ++__i) { |
| 1788 | + __node_holder& __nh = __nodes[__randomized_indices[__i]].__nh; |
| 1789 | + __node_pointer __np = __nh->__upcast(); |
| 1790 | + if _LIBCPP_CONSTEXPR_SINCE_CXX17 (_UniqueKeys) { |
| 1791 | + __node_insert_unique_perform(__np); |
| 1792 | + } else { |
| 1793 | + __next_pointer __pn = __node_insert_multi_prepare(__np->__hash(), __np->__get_value()); |
| 1794 | + __node_insert_multi_perform(__np, __pn); |
| 1795 | + } |
| 1796 | + __nh.release(); |
| 1797 | + } |
| 1798 | +#endif |
| 1799 | +} |
| 1800 | + |
1744 | 1801 | template <class _Tp, class _Hash, class _Equal, class _Alloc> |
1745 | 1802 | template <class _Key> |
1746 | 1803 | typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator |
|
0 commit comments