Skip to content

Commit c4cf9aa

Browse files
committed
libstdc++: [_Hashtable] Use RAII type to manage rehash functor state
Replace usage of __try/__catch with a RAII type to restore rehash functor state when needed. libstdc++-v3/ChangeLog: * include/bits/hashtable_policy.h (_RehashStateGuard): New. (_Insert_base<>::_M_insert_range(_IIt, _IIt, const _NodeGet&, false_type)): Adapt. * include/bits/hashtable.h (__rehash_guard_t): New. (__rehash_state): Remove. (_M_rehash): Remove. (_M_rehash_aux): Rename into _M_rehash. (_M_assign_elements, _M_insert_unique_node, _M_insert_multi_node): Adapt. (rehash): Adapt.
1 parent 38b396d commit c4cf9aa

File tree

2 files changed

+45
-50
lines changed

2 files changed

+45
-50
lines changed

libstdc++-v3/include/bits/hashtable.h

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
234234
_RehashPolicy, _Traits>;
235235
using __enable_default_ctor
236236
= _Hashtable_enable_default_ctor<_Equal, _Hash, _Alloc>;
237+
using __rehash_guard_t
238+
= __detail::_RehashStateGuard<_RehashPolicy>;
237239

238240
public:
239241
typedef _Key key_type;
@@ -264,7 +266,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
264266

265267
private:
266268
using __rehash_type = _RehashPolicy;
267-
using __rehash_state = typename __rehash_type::_State;
268269

269270
using __unique_keys = typename __traits_type::__unique_keys;
270271

@@ -1200,14 +1201,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
12001201

12011202
private:
12021203
// Helper rehash method used when keys are unique.
1203-
void _M_rehash_aux(size_type __bkt_count, true_type __uks);
1204+
void _M_rehash(size_type __bkt_count, true_type __uks);
12041205

12051206
// Helper rehash method used when keys can be non-unique.
1206-
void _M_rehash_aux(size_type __bkt_count, false_type __uks);
1207-
1208-
// Unconditionally change size of bucket array to n, restore
1209-
// hash policy state to __state on exception.
1210-
void _M_rehash(size_type __bkt_count, const __rehash_state& __state);
1207+
void _M_rehash(size_type __bkt_count, false_type __uks);
12111208
};
12121209

12131210
// Definitions of class template _Hashtable's out-of-line member functions.
@@ -1337,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
13371334
{
13381335
__buckets_ptr __former_buckets = nullptr;
13391336
std::size_t __former_bucket_count = _M_bucket_count;
1340-
const __rehash_state& __former_state = _M_rehash_policy._M_state();
1337+
__rehash_guard_t __rehash_guard(_M_rehash_policy);
13411338

13421339
if (_M_bucket_count != __ht._M_bucket_count)
13431340
{
@@ -1359,14 +1356,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
13591356
_M_assign(std::forward<_Ht>(__ht), __roan);
13601357
if (__former_buckets)
13611358
_M_deallocate_buckets(__former_buckets, __former_bucket_count);
1359+
__rehash_guard._M_guarded_obj = nullptr;
13621360
}
13631361
__catch(...)
13641362
{
13651363
if (__former_buckets)
13661364
{
13671365
// Restore previous buckets.
13681366
_M_deallocate_buckets();
1369-
_M_rehash_policy._M_reset(__former_state);
13701367
_M_buckets = __former_buckets;
13711368
_M_bucket_count = __former_bucket_count;
13721369
}
@@ -2142,17 +2139,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
21422139
__node_ptr __node, size_type __n_elt)
21432140
-> iterator
21442141
{
2145-
const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2142+
__rehash_guard_t __rehash_guard(_M_rehash_policy);
21462143
std::pair<bool, std::size_t> __do_rehash
21472144
= _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
21482145
__n_elt);
21492146

21502147
if (__do_rehash.first)
21512148
{
2152-
_M_rehash(__do_rehash.second, __saved_state);
2149+
_M_rehash(__do_rehash.second, true_type{});
21532150
__bkt = _M_bucket_index(__code);
21542151
}
21552152

2153+
__rehash_guard._M_guarded_obj = nullptr;
21562154
this->_M_store_code(*__node, __code);
21572155

21582156
// Always insert at the beginning of the bucket.
@@ -2172,13 +2170,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
21722170
__hash_code __code, __node_ptr __node)
21732171
-> iterator
21742172
{
2175-
const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2173+
__rehash_guard_t __rehash_guard(_M_rehash_policy);
21762174
std::pair<bool, std::size_t> __do_rehash
21772175
= _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
21782176

21792177
if (__do_rehash.first)
2180-
_M_rehash(__do_rehash.second, __saved_state);
2178+
_M_rehash(__do_rehash.second, false_type{});
21812179

2180+
__rehash_guard._M_guarded_obj = nullptr;
21822181
this->_M_store_code(*__node, __code);
21832182
const key_type& __k = _ExtractKey{}(__node->_M_v());
21842183
size_type __bkt = _M_bucket_index(__code);
@@ -2509,39 +2508,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
25092508
_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
25102509
rehash(size_type __bkt_count)
25112510
{
2512-
const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2511+
__rehash_guard_t __rehash_guard(_M_rehash_policy);
25132512
__bkt_count
25142513
= std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1),
25152514
__bkt_count);
25162515
__bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count);
25172516

25182517
if (__bkt_count != _M_bucket_count)
2519-
_M_rehash(__bkt_count, __saved_state);
2520-
else
2521-
// No rehash, restore previous state to keep it consistent with
2522-
// container state.
2523-
_M_rehash_policy._M_reset(__saved_state);
2524-
}
2525-
2526-
template<typename _Key, typename _Value, typename _Alloc,
2527-
typename _ExtractKey, typename _Equal,
2528-
typename _Hash, typename _RangeHash, typename _Unused,
2529-
typename _RehashPolicy, typename _Traits>
2530-
void
2531-
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2532-
_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2533-
_M_rehash(size_type __bkt_count, const __rehash_state& __state)
2534-
{
2535-
__try
2536-
{
2537-
_M_rehash_aux(__bkt_count, __unique_keys{});
2538-
}
2539-
__catch(...)
25402518
{
2541-
// A failure here means that buckets allocation failed. We only
2542-
// have to restore hash policy previous state.
2543-
_M_rehash_policy._M_reset(__state);
2544-
__throw_exception_again;
2519+
_M_rehash(__bkt_count, __unique_keys{});
2520+
__rehash_guard._M_guarded_obj = nullptr;
25452521
}
25462522
}
25472523

@@ -2553,7 +2529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
25532529
void
25542530
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
25552531
_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2556-
_M_rehash_aux(size_type __bkt_count, true_type /* __uks */)
2532+
_M_rehash(size_type __bkt_count, true_type /* __uks */)
25572533
{
25582534
__buckets_ptr __new_buckets = _M_allocate_buckets(__bkt_count);
25592535
__node_ptr __p = _M_begin();
@@ -2596,7 +2572,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
25962572
void
25972573
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
25982574
_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2599-
_M_rehash_aux(size_type __bkt_count, false_type /* __uks */)
2575+
_M_rehash(size_type __bkt_count, false_type /* __uks */)
26002576
{
26012577
__buckets_ptr __new_buckets = _M_allocate_buckets(__bkt_count);
26022578
__node_ptr __p = _M_begin();

libstdc++-v3/include/bits/hashtable_policy.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,25 @@ namespace __detail
721721
std::size_t _M_next_resize;
722722
};
723723

724+
template<typename _RehashPolicy>
725+
struct _RehashStateGuard
726+
{
727+
_RehashPolicy* _M_guarded_obj;
728+
typename _RehashPolicy::_State _M_prev_state;
729+
730+
_RehashStateGuard(_RehashPolicy& __policy)
731+
: _M_guarded_obj(std::__addressof(__policy))
732+
, _M_prev_state(__policy._M_state())
733+
{ }
734+
_RehashStateGuard(const _RehashStateGuard&) = delete;
735+
736+
~_RehashStateGuard()
737+
{
738+
if (_M_guarded_obj)
739+
_M_guarded_obj->_M_reset(_M_prev_state);
740+
}
741+
};
742+
724743
// Base classes for std::_Hashtable. We define these base classes
725744
// because in some cases we want to do different things depending on
726745
// the value of a policy class. In some cases the policy class
@@ -1012,24 +1031,24 @@ namespace __detail
10121031
_M_insert_range(_InputIterator __first, _InputIterator __last,
10131032
const _NodeGetter& __node_gen, false_type __uks)
10141033
{
1015-
using __rehash_type = typename __hashtable::__rehash_type;
1016-
using __rehash_state = typename __hashtable::__rehash_state;
1017-
using pair_type = std::pair<bool, std::size_t>;
1034+
using __rehash_guard_t = typename __hashtable::__rehash_guard_t;
1035+
using __pair_type = std::pair<bool, std::size_t>;
10181036

10191037
size_type __n_elt = __detail::__distance_fw(__first, __last);
10201038
if (__n_elt == 0)
10211039
return;
10221040

10231041
__hashtable& __h = _M_conjure_hashtable();
1024-
__rehash_type& __rehash = __h._M_rehash_policy;
1025-
const __rehash_state& __saved_state = __rehash._M_state();
1026-
pair_type __do_rehash = __rehash._M_need_rehash(__h._M_bucket_count,
1027-
__h._M_element_count,
1028-
__n_elt);
1042+
__rehash_guard_t __rehash_guard(__h._M_rehash_policy);
1043+
__pair_type __do_rehash
1044+
= __h._M_rehash_policy._M_need_rehash(__h._M_bucket_count,
1045+
__h._M_element_count,
1046+
__n_elt);
10291047

10301048
if (__do_rehash.first)
1031-
__h._M_rehash(__do_rehash.second, __saved_state);
1049+
__h._M_rehash(__do_rehash.second, __uks);
10321050

1051+
__rehash_guard._M_guarded_obj = nullptr;
10331052
for (; __first != __last; ++__first)
10341053
__h._M_insert(*__first, __node_gen, __uks);
10351054
}

0 commit comments

Comments
 (0)