@@ -1024,7 +1024,21 @@ private:
1024
1024
}
1025
1025
_LIBCPP_HIDE_FROM_ABI void __move_assign_alloc (__hash_table&, false_type) _NOEXCEPT {}
1026
1026
1027
- _LIBCPP_HIDE_FROM_ABI void __deallocate_node (__next_pointer __np) _NOEXCEPT;
1027
+ _LIBCPP_HIDE_FROM_ABI void __deallocate_node (__node_pointer __nd) _NOEXCEPT {
1028
+ auto & __alloc = __node_alloc ();
1029
+ __node_traits::destroy (__alloc, std::addressof (__nd->__get_value ()));
1030
+ std::__destroy_at (std::__to_address (__nd));
1031
+ __node_traits::deallocate (__alloc, __nd, 1 );
1032
+ }
1033
+
1034
+ _LIBCPP_HIDE_FROM_ABI void __deallocate_node_list (__next_pointer __np) _NOEXCEPT {
1035
+ while (__np != nullptr ) {
1036
+ __next_pointer __next = __np->__next_ ;
1037
+ __deallocate_node (__np->__upcast ());
1038
+ __np = __next;
1039
+ }
1040
+ }
1041
+
1028
1042
_LIBCPP_HIDE_FROM_ABI __next_pointer __detach () _NOEXCEPT;
1029
1043
1030
1044
template <class _From , class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
@@ -1162,7 +1176,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() {
1162
1176
static_assert (is_copy_constructible<hasher>::value, " Hasher must be copy-constructible." );
1163
1177
#endif
1164
1178
1165
- __deallocate_node (__first_node_.__next_ );
1179
+ __deallocate_node_list (__first_node_.__next_ );
1166
1180
}
1167
1181
1168
1182
template <class _Tp , class _Hash , class _Equal , class _Alloc >
@@ -1238,7 +1252,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __other)
1238
1252
// At this point we either have consumed the whole incoming hash table, or we don't have any more nodes to reuse in
1239
1253
// the destination. Either continue with constructing new nodes, or deallocate the left over nodes.
1240
1254
if (__own_iter->__next_ ) {
1241
- __deallocate_node (__own_iter->__next_ );
1255
+ __deallocate_node_list (__own_iter->__next_ );
1242
1256
__own_iter->__next_ = nullptr ;
1243
1257
} else {
1244
1258
__copy_construct (__other_iter, __own_iter, __current_chash);
@@ -1249,19 +1263,6 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __other)
1249
1263
return *this ;
1250
1264
}
1251
1265
1252
- template <class _Tp , class _Hash , class _Equal , class _Alloc >
1253
- void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np) _NOEXCEPT {
1254
- __node_allocator& __na = __node_alloc ();
1255
- while (__np != nullptr ) {
1256
- __next_pointer __next = __np->__next_ ;
1257
- __node_pointer __real_np = __np->__upcast ();
1258
- __node_traits::destroy (__na, std::addressof (__real_np->__get_value ()));
1259
- std::__destroy_at (std::addressof (*__real_np));
1260
- __node_traits::deallocate (__na, __real_np, 1 );
1261
- __np = __next;
1262
- }
1263
- }
1264
-
1265
1266
template <class _Tp , class _Hash , class _Equal , class _Alloc >
1266
1267
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer
1267
1268
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach() _NOEXCEPT {
@@ -1317,11 +1318,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
1317
1318
}
1318
1319
#if _LIBCPP_HAS_EXCEPTIONS
1319
1320
} catch (...) {
1320
- __deallocate_node (__cache);
1321
+ __deallocate_node_list (__cache);
1321
1322
throw ;
1322
1323
}
1323
1324
#endif // _LIBCPP_HAS_EXCEPTIONS
1324
- __deallocate_node (__cache);
1325
+ __deallocate_node_list (__cache);
1325
1326
}
1326
1327
const_iterator __i = __u.begin ();
1327
1328
while (__u.size () != 0 )
@@ -1360,11 +1361,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
1360
1361
}
1361
1362
#if _LIBCPP_HAS_EXCEPTIONS
1362
1363
} catch (...) {
1363
- __deallocate_node (__cache);
1364
+ __deallocate_node_list (__cache);
1364
1365
throw ;
1365
1366
}
1366
1367
#endif // _LIBCPP_HAS_EXCEPTIONS
1367
- __deallocate_node (__cache);
1368
+ __deallocate_node_list (__cache);
1368
1369
}
1369
1370
for (; __first != __last; ++__first)
1370
1371
__emplace_unique (*__first);
@@ -1390,11 +1391,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
1390
1391
}
1391
1392
#if _LIBCPP_HAS_EXCEPTIONS
1392
1393
} catch (...) {
1393
- __deallocate_node (__cache);
1394
+ __deallocate_node_list (__cache);
1394
1395
throw ;
1395
1396
}
1396
1397
#endif // _LIBCPP_HAS_EXCEPTIONS
1397
- __deallocate_node (__cache);
1398
+ __deallocate_node_list (__cache);
1398
1399
}
1399
1400
for (; __first != __last; ++__first)
1400
1401
__emplace_multi (*__first);
@@ -1427,7 +1428,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT {
1427
1428
template <class _Tp , class _Hash , class _Equal , class _Alloc >
1428
1429
void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear () _NOEXCEPT {
1429
1430
if (size () > 0 ) {
1430
- __deallocate_node (__first_node_.__next_ );
1431
+ __deallocate_node_list (__first_node_.__next_ );
1431
1432
__first_node_.__next_ = nullptr ;
1432
1433
size_type __bc = bucket_count ();
1433
1434
for (size_type __i = 0 ; __i < __bc; ++__i)
@@ -1955,12 +1956,57 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p) {
1955
1956
template <class _Tp , class _Hash , class _Equal , class _Alloc >
1956
1957
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1957
1958
__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase (const_iterator __first, const_iterator __last) {
1958
- for (const_iterator __p = __first; __first != __last; __p = __first) {
1959
- ++__first;
1960
- erase (__p);
1959
+ if (__first == __last)
1960
+ return iterator (__last.__node_ );
1961
+
1962
+ // current node
1963
+ __next_pointer __current = __first.__node_ ;
1964
+ size_type __bucket_count = bucket_count ();
1965
+ size_t __chash = std::__constrain_hash (__current->__hash (), __bucket_count);
1966
+ // find previous node
1967
+ __next_pointer __before_first = __bucket_list_[__chash];
1968
+ for (; __before_first->__next_ != __current; __before_first = __before_first->__next_ )
1969
+ ;
1970
+
1971
+ __next_pointer __last_node = __last.__node_ ;
1972
+
1973
+ // If __before_first is in the same bucket (i.e. the first element we erase is not the first in the bucket), clear
1974
+ // this bucket first without re-linking it
1975
+ if (__before_first != __first_node_.__ptr () &&
1976
+ std::__constrain_hash (__before_first->__hash (), __bucket_count) == __chash) {
1977
+ while (__current != __last_node) {
1978
+ if (auto __next_chash = std::__constrain_hash (__current->__hash (), __bucket_count); __next_chash != __chash) {
1979
+ __chash = __next_chash;
1980
+ break ;
1981
+ }
1982
+ auto __next = __current->__next_ ;
1983
+ __deallocate_node (__current->__upcast ());
1984
+ __current = __next;
1985
+ --__size_;
1986
+ }
1961
1987
}
1962
- __next_pointer __np = __last.__node_ ;
1963
- return iterator (__np);
1988
+
1989
+ while (__current != __last_node) {
1990
+ auto __next = __current->__next_ ;
1991
+ __deallocate_node (__current->__upcast ());
1992
+ __current = __next;
1993
+ --__size_;
1994
+
1995
+ // When switching buckets, set the old bucket to be empty and update the next bucket to have __before_first as its
1996
+ // before-first element
1997
+ if (__next) {
1998
+ if (auto __next_chash = std::__constrain_hash (__next->__hash (), __bucket_count); __next_chash != __chash) {
1999
+ __bucket_list_[__chash] = nullptr ;
2000
+ __chash = __next_chash;
2001
+ __bucket_list_[__chash] = __before_first;
2002
+ }
2003
+ }
2004
+ }
2005
+
2006
+ // re-link __before_first with __last
2007
+ __before_first->__next_ = __current;
2008
+
2009
+ return iterator (__last.__node_ );
1964
2010
}
1965
2011
1966
2012
template <class _Tp , class _Hash , class _Equal , class _Alloc >
0 commit comments